2012-02-23 17 views
16

Czy ktoś mógłby wyjaśnić, lub wskazać mi jakieś wyjaśnienie, czym jest R-Value? Nie jestem do końca pewien, co to jest, a mój projekt musi go włączyć. Tutaj jest wykazanie co R-Value jest (pierwsza część jest r_string.hpp):Czym dokładnie jest wartość R w 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

możliwy duplikat [Co oznacza T && w C++ 11?] (Http://stackoverflow.com/questions/5481539/what-does-t-mean-in-c11) –

+2

możliwy duplikat [Czym są wartości r, wartości l, x wartości, wartości gl i prvalues?] (http://stackoverflow.com/questions/3601602/what-are- wartości-wartościach-wartościach-wartościach-i-wartościach) –

+0

@ Nicol: On pyta o wartość , a nie wartość odniesienia rvalue. Więc bardziej podoba mi się to pytanie. Ale absolutnie pozytywnie dupe. –

Odpowiedz

24

„Może ktoś wyjaśnić lub wskaż mnie do jakiegoś wyjaśnienia, co R-Value jest? nie jestem pewien, co to jest”

Termin lwartość początkowo odnosiła się do wyrażenia, które mogą być takie lewo strony cesji. Odpowiednio, wartość rvalue (chociaż, jak pamiętam, termin ten nie był używany przez standard C89), początkowo było dokładnie odwrotnie: wyrażenie, które nie mogło być lewą stroną przypisania, ale mogło to być tylko prawo ręka.

C++ 11 skomplikowało to przez dodanie kilku bardziej wyrafinowanych terminów, ale skoncentrujmy się na znaczeniach C++ 03.

Na przykład, jeśli masz

int x; 

następnie przypisanie x = 42 jest OK, więc x jest lwartością wypowiedzi.

Jako kontrprzykład, przydział x+0 = 42 nie jest prawidłowy, więc x+0 jest wyrażeniem rvalue.

Podobnie jak wyrażenie 2+2, jest to wyrażenie rvalue.

Tak więc, jeśli warunek jest taki, że program powinien zawierać wartość r, należy wpisać 2+2 lub np. (bardziej zaawansowany) 6*7, w main. Nie ma numeru const. W języku C++ z const należy zignorować wartość const w celu oznaczenia wyrażenia jako lwartości lub rwartości. Punktem krytycznym jest wtedy, czy wyrażenie gwarantowane odnosi się do obiektu w pamięci, obiektu z adresem: jeśli tak, wówczas wyrażenie jest lwartością.

Typ referencyjny oznacza lwartość, ponieważ wyrażenie typu odniesienia odnosi się koniecznie do obiektu z adresem pamięci, tj. Że wyrażenie jest lwartością.

Jednak oprócz referencji nie ma połączenia między typem a lwartością/rwartością. Na przykład zarówno x, jak i x+0 są wyrażeniami typu int i dają taką samą wartość int. Ale ten pierwszy jest wyrażeniem lwartościowym, podczas gdy drugi jest wyrażeniem rvalue.

Zgodnie z ogólną zasadą, jeśli można zastosować wbudowany operator adresu, to jest to wyrażenie lwartości, w przeciwnym razie jest to wyrażenie rvalue.

+3

Definicja "l-wartości" standardu C ma historię kratkę; definicje C90 i C99 miały poważne problemy. C11 definiuje lwartość jako "wyrażenie ... które potencjalnie oznacza obiekt" ("potencjalnie" oznacza, że ​​'* ptr' jest lwartością, nawet jeśli' ptr == NULL'). Zmienione brzmienie C11 było moim pomysłem.

+0

@KeithThompson: Czy wiesz, że link, który masz na swoim profilu SO jest martwy? –

+0

@CamJackson: Który? GitHub i Kariera łączą obie prace dla mnie. –

6

Termin RValue wywodzi się z jego historycznym kontekście --- to było coś, co może pójść tylko po stronie prawej cesji, w przeciwieństwie do lwartości, które mogłyby pójść na lewej stronie zadania. Tak więc nazwana zmienna (na przykład x) jest wartością l, ale dosłowna liczba całkowita (np. 42) jest wartością r.

Jednak w nowoczesnym C++ jest bardziej zniuansowany.

W języku C++ wartość rublowa jest nienazwanym obiektem lub członkiem takiego obiektu, który nie jest odniesieniem.

Kilka przykładów:

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 

W (1), tymczasowy std::string obiekt utworzony z łańcucha dosłownym jest rvalue.

W (2) obiekt zwrócony z foo() jest wartością r.

W (3), bar() zwraca referencję, więc nie ma wartości r.

W (4) tymczasowy obiekt std::string niejawnie utworzony z literału łańcuchowego jest wartością r.

W (5) tymczasowy obiekt X jest wartością rwartową, dlatego też jest to element s.

Wyrażenia, takie jak x+3, zwykle powodują czasowe, a zatem są rwartością. Jednakże, jeśli do zmiany typu zwracanego na referencję użyto przeciążenia operatora, wynikiem jest l-wartość.