Что такое R-значение в C ++? - PullRequest
       1

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

22 голосов
/ 23 февраля 2012

Может ли кто-нибудь объяснить или указать мне какое-то объяснение, что такое 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;

}

Ответы [ 2 ]

30 голосов
/ 23 февраля 2012

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

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

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

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

int x;

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

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

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

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

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

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

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

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

13 голосов
/ 23 февраля 2012

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

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

В C ++ значение r - это неназванный объект или член такого объекта, который не является ссылкой.

Некоторые примеры:

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() возвращает aссылка, таким образом, нет никаких значений.

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...