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

问题描述 投票:21回答:2

有人可以向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;

}
c++ c++11
2个回答
30
投票

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

术语“左值”最初指的是可能是赋值左侧的表达式。相应地,一个右值(虽然我记得那个术语没有被C89标准使用),但最初恰恰相反:一个表达式不能作为任务的左手边,但这只能是右手边。

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

例如,如果你有

int x;

赋值x = 42没问题,所以x是一个左值表达式。

作为一个反例,分配x+0 = 42不行,所以x+0是一个右值表达式。

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

因此,如果要求您的程序应包含右值,那么只需编写2+2或者例如(更高级)6*7,在main

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

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

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

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


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

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

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

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

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

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

x+3这样的表达式通常会导致临时性,因此是一个rvalue。但是,如果已使用运算符重载将返回类型更改为引用,则结果为左值。

© www.soinside.com 2019 - 2024. All rights reserved.