Что такое R-значение в С++? - программирование
Подтвердить что ты не робот

Что такое R-значение в С++?

Может кто-нибудь объяснить или указать мне какое-то объяснение того, что такое R-Value? Я не совсем уверен, что это такое, и мой проект должен включить его. Вот демонстрация того, что такое R-значение (первая часть - 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;

}
4b9b3361

Ответ 1

"Может кто-нибудь объяснить или указать мне какое-то объяснение, что такое R-Value? Я не уверен, что это такое"

Термин lvalue первоначально ссылался на выражение, которое может быть левой частью задания. Соответственно, rvalue (хотя, насколько я помню, этот термин не использовался стандартом C89), изначально было просто противоположным: выражение, которое не могло быть левой частью задания, но это могло бы только правая сторона.

С++ 11 усложнил это, добавив еще несколько нюансных терминов, но давайте сосредоточимся на значениях С++ 03.

Например, если у вас есть

int x;

тогда присваивание x = 42 ОК, поэтому x является выражением lvalue.

В качестве встречного примера, присваивание x+0 = 42 не является ОК, поэтому x+0 является выражением rvalue.

А также выражение 2+2, это выражение rvalue.

Итак, если требование состоит в том, что ваша программа должна включать rvalue, тогда просто напишите 2+2 или, например. (более продвинутый) 6*7, в main.

У оригинала C не было const. В С++ с const вы должны игнорировать const для обозначения выражения как lvalue или rvalue. Критической точкой является то, является ли гарантированное выражение ссылкой на объект в памяти, объект с адресом: если это так, то выражение является lvalue.

Тип ссылки подразумевает lvalue, потому что выражение ссылочного типа обязательно ссылается на объект с адресом памяти, то есть это выражение является lvalue.

Однако, кроме ссылок, нет связи между типом и lvalue/rvalue. Например, оба x и x+0 являются выражениями типа int, и они дают то же значение int. Но первое является выражением lvalue, в то время как последнее является выражением rvalue.

Как правило, если вы можете применить встроенный оператор адреса, то это выражение lvalue, и в противном случае это выражение rvalue.

Ответ 2

Термин rvalue вытекает из его исторического контекста - это то, что может быть только в правой части задания, в отличие от lvalue который может идти по левой стороне задания. Таким образом, именованная переменная (например, x) является значением lvalue, но буквальное целое число (например, 42) является rvalue.

Однако в современном С++ он более тонкий, чем этот.

В С++ 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, созданный из строкового литерала, является rvalue.

В (2) объект, возвращаемый из foo(), является rvalue.

В (3), bar() возвращает ссылку, поэтому нет rvalues.

В (4) временный объект std::string, неявно созданный из строкового литерала, является rvalue.

В (5) временный объект x является значением r, поэтому поэтому член s.

Выражения, такие как x+3, как правило, приводят к временному, что, таким образом, является rvalue. Однако, если перегрузка оператора была использована для изменения типа возврата на ссылку, то результатом будет lvalue.