2012-02-23 21 views
16

¿Podría alguien explicarme o indicarme algún tipo de explicación sobre qué es R-Value? No estoy seguro de qué es, y mi proyecto tiene que incorporarlo. Aquí es una demostración de lo que es el valor R (primera parte es el r_string.hpp):¿Qué es exactamente un R-Value en C++?

#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

posible duplicado de [¿Qué significa T && en C++ 11?] (Http://stackoverflow.com/questions/5481539/what-does-t-mean-in-c11) –

+2

posible duplicado de [Qué son rvalues, lvalues, xvalues, glvalues, y prvalues?] (http://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues) –

+0

@Nicol: pregunta por un valor , no una referencia rvalue Entonces me gusta esta pregunta mejor. Pero absolutamente un tonto. –

Respuesta

24

"Podría alguien explicar, o que me señale algún tipo de explicación, de lo que el valor R es? no estoy realmente seguro de lo que es"

el término lvalue originalmente se refería a una expresión que podría ser la izquierda lado de una cesión. En consecuencia, un rvalue (aunque como recuerdo ese término no fue utilizado por el estándar C89), originalmente era todo lo contrario: una expresión que no podía ser el lado izquierdo de una asignación, pero que solo podía ser el derecha lado de la mano.

C++ 11 esto se complica añadiendo varios términos más matizados, pero concentrémonos en los significados de C++ 03.

Por ejemplo, si usted tiene

int x; 

entonces la tarea x = 42 está bien, por lo que es una expresión x lvalue.

Como un contraejemplo, la asignación x+0 = 42 no es correcta, por lo que x+0 es una expresión rvalue.

Y así es la expresión 2+2, es una expresión rvalue.

Por lo tanto, si el requisito es que su programa incluya un valor r, simplemente escriba 2+2 o p. Ej. (más avanzado) 6*7, en main.

Original C no tenía const. En C++, con const, debe descartar el const con el fin de designar una expresión como lvalue o rvalue. El punto crítico es entonces si la expresión garantizada se refiere a un objeto en la memoria, un objeto con una dirección: si es así, entonces la expresión es un valor l.

Un tipo de referencia implica lvalue, porque una expresión de tipo de referencia necesariamente se refiere a un objeto con una dirección de memoria, es decir, esa expresión es un valor l.

Sin embargo, a excepción de las referencias, no hay conexión entre el tipo y lvalue/rvalue. Por ejemplo, tanto x como x+0 son expresiones del tipo int, y producen el mismo valor int. Pero el primero es una expresión lvalue, mientras que el último es una expresión rvalue.

Como regla general, si puede aplicar el operador de dirección integrado, entonces es una expresión lvalue y, de lo contrario, es una expresión rvalue.

+3

La definición del estándar C de "lvalue" tiene una historia accidentada; las definiciones C90 y C99 tenían serios problemas. C11 define un lvalue como "una expresión ... que designa potencialmente un objeto" (el "potencialmente" significa que '* ptr' es un lvalue incluso si' ptr == NULL'). La redacción revisada de C11 fue idea mía.

+0

@KeithThompson: ¿Sabe que el enlace que tiene en su perfil SO está muerto? –

+0

@CamJackson: ¿Cuál? Los enlaces de GitHub y Careers funcionan tanto para mí. –

6

El término rvalue deriva de su contexto histórico --- fue algo que sólo podía ir en el lado derecho de una asignación, en lugar de un lvalue que podría ir en el lado izquierdo de una tarea. Por lo tanto, una variable con nombre (por ejemplo, x) es un valor l, pero un entero literal (por ejemplo, 42) es un valor r.

Sin embargo, en el moderno C++ tiene más matices que eso.

En C++, un rvalue es un objeto sin nombre o un miembro de dicho objeto que no es una referencia.

Algunos ejemplos:

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 

En (1), el std::string objeto temporal creada a partir de la cadena literal es un valor de lado derecho.

En (2), el objeto devuelto por foo() es un valor r.

En (3), bar() devuelve una referencia por lo que no hay valores r.

En (4), el objeto temporal std::string creado implícitamente a partir del literal de cadena es un valor r.

En (5), el objeto temporal X es un valor r, por lo que también lo es el miembro s.

Expresiones como x+3 normalmente dan como resultado un temporal, que es, por lo tanto, un valor r. Sin embargo, si la sobrecarga del operador se ha utilizado para cambiar el tipo de retorno a una referencia, el resultado es un valor l.