2012-02-23 413 views
16

有人可以解釋一下,或者指出我對R值是什麼的某種解釋嗎?我不確定它是什麼,我的項目必須將其納入。以下是對R值(第一部分是r_string.hpp)演示:C++中的R值究竟是什麼?

#include <algorithm> 
#include <iostream> 

template <typename CHAR_T = char> 

class basic_rstring { 
public: 
    typedef CHAR_T value_type; 
    typedef CHAR_T* pointer_type; 
    typedef CHAR_T const* pointer_const_type; 
private: 
    pointer_type _data; 
    std::size_t  _length; 
public: 
    basic_rstring() : _data(nullptr), _length(0) 
    { 
     std::cout << "Default ctor\n"; 
    } 

    basic_rstring(pointer_const_type s) 
     : _data(nullptr) 
     , _length(0) 
    { 
     std::cout << "Literal ctor: " << s << std::endl; 
     _length = strlen(s); 
     _data = new value_type[ _length + 1 ]; 
     std::copy(s, s + _length + 1, _data); 
    } 

    basic_rstring(basic_rstring const& s)  
     : _data(nullptr) 
     , _length(s._length) 
    { 
     std::cout << "Copy ctor: " << s.c_str() << std::endl; 
     _data = new value_type [ _length + 1 ]; 
     std::copy(s._data, s._data + s._length + 1, _data); 
    } 

    basic_rstring(basic_rstring && s)  //move constructor 
     : _data(s._data) 
     , _length(s._length) 
    { 
     std::cout << "Move ctor: " << s.c_str() << std::endl; 
     s._data = nullptr; 
     s._length = 0; 
    } 

    ~basic_rstring() 
    { 
     if(_data) 
      std::cout << "dtor: " << _data << "\n"; 
     else 
      std::cout << "NULL dtor\n"; 
     delete [] _data; 
    } 

    basic_rstring& operator = (basic_rstring const& s); 
    basic_rstring& operator = (basic_rstring && s) 
    { 
     std::cout << "RValue assignment: " << s.c_str(); 
     if(_data) 
      std::cout << " deleting...." << std::endl; 
     else 
      std::cout << " no delete..." << std::endl; 
     delete [] _data; 
     _data = s._data; 
     s._data = nullptr; 
     _length = s._length; 
     s._length = 0; 
     return *this; 
    } 

    pointer_const_type c_str() const { return _data; } 

}; 

template <typename CHAR_T> 
basic_rstring<CHAR_T>& basic_rstring<CHAR_T>::operator = (basic_rstring const& s) 
{ 
    std::cout << "Copy assignment: " << s.c_str() << std::endl; 
    pointer_type newData = new value_type [ s._length + 1 ]; 
    std::copy(s._data, s._data + s._length + 1, newData); 
    _length = s._length; 
    delete [] _data; 
    _data = newData; 
    return *this; 
} 

typedef basic_rstring<char> String; 
typedef basic_rstring<wchar_t> wString; 


#define _SCL_SECURE_NO_WARNINGS 
#include "Rstring.hpp" 
using namespace std; 
#define BOOST_TEST_MODULE move_test 
#include <boost/test/unit_test.hpp> 

template <typename T_> 
void old_swap(T_& a, T_&b) 
{ 
    T_ hold = a; 
    a = b; 
    b = hold; 
} 

BOOST_AUTO_TEST_CASE(stuff) 
{ 
    String s("Bert"); 
    String t("Ernie"); 
    cout << "Old swap" << endl; 
    old_swap(s,t); 
    BOOST_CHECK(!strcmp("Bert", t.c_str())); 
    BOOST_CHECK(!strcmp("Ernie", s.c_str())); 

    cout << "New swap" << endl; 
    swap(s,t); 
    BOOST_CHECK(!strcmp("Bert", s.c_str())); 
    BOOST_CHECK(!strcmp("Ernie", t.c_str())); 

    cout << "\nDone." << endl; 

} 
+2

可能重複[在C++ 11中T &&的意思是什麼?](http://stackoverflow.com/questions/5481539/what-does-t-mean-in-c11) – 2012-02-23 02:06:35

+2

可能重複[什麼是rvalues,lvalues,xvalues,glvalues和prvalues?](http://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues) – 2012-02-23 03:22:10

+0

@Nicol:他問的是一個右值,而不是右值引用。所以我更喜歡這個問題。但絕對是一個愚蠢的積極。 – 2012-02-23 03:22:48

回答

24

「有人能解釋或指向我某種東西R值的解釋,?我真的不知道它是什麼」

術語左值最初指的可能是留下分配的右手邊的表達式。相應地,一個右值(儘管我記得C89標準沒有使用該術語),原本恰恰相反:一個表達式不可能是任務的左手邊,但這隻能是右邊的手邊。

C++ 11通過添加更多細微差別的術語使其複雜化,但讓我們專注於C++ 03的含義。

舉例來說,如果你有

int x; 

然後分配x = 42是確定的,所以x是一個左值表達式。

作爲反例,分配x+0 = 42不正確,所以x+0是一個右值表達式。

表達式2+2也是一個右值表達式。

所以,如果要求你的程序應該包括一個右值,那麼只需寫2+2或者(更高級)6*7main

原始C沒有const。在C++中,爲了將表達式指定爲左值或右值,您不得不忽略const。關鍵的一點是,表達式保證是否指內存中的對象,即具有地址的對象:如果是,則表達式是左值。

引用類型意味着左值,因爲引用類型的表達式必然引用具有內存地址的對象,即該表達式是左值。

但是,除了引用之外,type和lvalue/rvalue之間沒有連接。例如,xx+0都是int類型的表達式,並且它們產生相同的int值。但前者是一個左值表達式,而後者是一個右值表達式。作爲一般規則,如果您可以應用內置的地址運算符,那麼它是一個左值表達式,否則它是一個右值表達式。

+3

C標準的「左值」的定義有一個方格的歷史; C90和C99的定義都有嚴重的問題。 C11將左值定義爲「可能指定對象的表達式」(「可能」意味着即使'ptr == NULL',* ptr'也是左值)。 C11的修改措辭是我的想法。 2012-02-23 04:43:39

+0

@KeithThompson:您是否知道您的SO配置文件中的鏈接已死? – 2012-02-23 05:28:34

+0

@CamJackson:哪一個? GitHub和Careers鏈接都適用於我。 – 2012-02-23 06:27:37

6

術語右值從它的歷史背景派生---那件事,只能去賦值的右手邊,而不是一個左值可能走在左邊的任務。因此,命名變量(例如x)是左值,但是文字整數(例如42)是右值。

但是,在現代C++中,它比這更微妙。

在C++中,右值是未命名的對象或不是引用的對象的成員。

一些例子:

std::string s; 

std::string foo(){ return "foo";} 

struct X { 
    std::string s; 
}; 

std::string& bar() {return s;} 

void baz(std::string const& x){} 

s=std::string("hello"); // 1 
s=foo();    // 2 
std::string s2=bar(); // 3 
baz("hello");   // 4 
s=X().s;    // 5 

在(1)中,從字符串文字創建的臨時std::string對象是一個rvalue。 (2)中,從foo()返回的對象是一個右值。

在(3)中,bar()返回一個引用,所以不存在右值。

在(4)中,從字符串文字中隱式創建的臨時std::string對象是一個右值。

在(5)中,臨時對象X是右值,因此s成員也是如此。

諸如x+3之類的表達式通常會導致一個臨時值,因此這是一個右值。但是,如果使用操作符重載將返回類型更改爲引用,則結果爲左值。