2012-02-23 414 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之类的表达式通常会导致一个临时值,因此这是一个右值。但是,如果使用操作符重载将返回类型更改为引用,则结果为左值。