究竟什么是C++中的R值?

Dav*_*ave 23 c++ c++11

有人可以向R-Value解释或指出某种解释吗?我不确定它是什么,我的项目必须加入它.下面是R-Value的演示(第一部分是r_string.hpp):

#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;

}
Run Code Online (Sandbox Code Playgroud)

Che*_*Alf 33

"有人可以向R-Value解释或指出某种解释吗?我不确定它是什么"

术语" 左值"最初指的是可能是赋值左侧的表达式.相应地,一个右值(虽然我记得这个词是不使用的C89标准),原本是正好相反:这不可能是一个分配的左手侧的表达式,但只能是在正确的右手边.

C++ 11通过添加几个细微的术语来解决这个问题,但让我们专注于C++ 03的含义.

例如,如果你有

int x;
Run Code Online (Sandbox Code Playgroud)

然后赋值x = 42是正确的,x左值表达式也是如此.

作为一个反例,分配x+0 = 42不正常,因此x+0是一个右值表达式.

表达式也是如此2+2,它是一个右值表达式.

因此,如果要求是,你的程序应该包括一个右值,然后只写2+2或如(更先进的)6*7main.

原来C没有const.在C++中,const您必须忽略将const表达式指定为左值或右值的目的.关键点是表达保证是否指向内存中的对象,具有地址的对象:如果是,则表达式是左值.

引用类型意味着左值,因为引用类型的表达式必然是指具有内存地址的对象,即该表达式是左值.

但是,除了引用之外,type和lvalue/rvalue之间没有任何关联.例如,这两个xx+0的类型的表达int,并且它们产生相同的int值.但前者是左值表达式,而后者是右值表达式.

作为一般规则,如果您可以应用内置地址运算符,那么它是一个左值表达式,否则它是一个右值表达式.

  • C标准对"左值"的定义有一个曲折的历史; C90和C99定义都存在严重问题.C11将左值定义为"可能指定对象的表达式"("可能"意味着即使`ptr == NULL`,`*ptr`也是左值).<BRAG> C11的修改措辞是我的想法.</ BRAG> (5认同)

Ant*_*ams 13

rvalue这个术语来源于它的历史背景 - 它只能在任务的右侧,而不是可以在任务的左侧进行的左值.因此,命名变量(例如x)是左值,但是文字整数(例如42)是右值.

然而,在现代C++中,它比那更细致.

在C++中,rvalue是未命名的对象或不是引用的此类对象的成员.

一些例子:

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
Run Code Online (Sandbox Code Playgroud)

在(1)中,std::string从字符串文字创建的临时对象是右值.

在(2)中,返回的对象foo()是右值.

在(3)中,bar()返回一个引用,因此没有rvalues.

在(4)中,std::string从字符串文字隐式创建的临时对象是右值.

在(5)中,临时X对象是右值,因此s成员也是如此.

诸如x+3典型的表达通常导致临时的,因此是右值.但是,如果已使用运算符重载将返回类型更改为引用,则结果为左值.