简体   繁体   中英

What exactly is an R-Value in C++?

Could someone explain, or point me to some sort of explanation, of what R-Value is? I'm not really sure what it is, and my project has to incorporate it. Here is a demonstration of what R-Value is(First part is the 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;

}

"Could someone explain, or point me to some sort of explanation, of what R-Value is? I'm not really sure what it is"

The term lvalue originally referred to an expression that could be the left hand side of an assignment. Correspondingly, an rvalue (although as I recall that term was not used by the C89 standard), was originally just the opposite: an expression that could not be the left hand side of an assignment, but that could only be the right hand side.

C++11 complicated this by adding several more nuanced terms, but let's concentrate on the C++03 meanings.

For example, if you have

int x;

then the assignment x = 42 is OK, so x is an lvalue expression.

As a counter-example, the assigment x+0 = 42 is not OK, so x+0 is an rvalue expression.

And so is the expression 2+2 , it's an rvalue expression.

So, if the requirement is that your program should include an rvalue, then just write 2+2 or eg (more advanced) 6*7 , in main .

Original C didn't have const . In C++, with const , you have to disregard the const for the purpose of designating an expression as lvalue or rvalue. The critical point is then whether the expression guaranteed refers to an object in memory, an object with an address: if so, then the expression is an lvalue.

A reference type implies lvalue, because an expression of reference type is necessarily referring to an object with a memory address, ie that expression is an lvalue.

However, other than references there's no connection between type and lvalue/rvalue. For example, both x and x+0 are expressions of type int , and they yield the same int value. But the former is an lvalue expression, while the latter is an rvalue expression.

As a general rule, if you can apply the built-in address operator, then it's an lvalue expression, and otherwise it's an rvalue expression.

The term rvalue derives from its historical context --- it was something that could only go on the Right-hand side of an assignment, as opposed to an lvalue which could go on the left-hand side of an assignment. Thus a named variable (eg x ) is an lvalue, but a literal integer (eg 42 ) is an rvalue.

However, in modern C++ it is more nuanced than that.

In C++, an rvalue is an unnamed object or a member of such an object which is not a reference.

Some examples:

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

In (1), the temporary std::string object created from the string literal is an rvalue.

In (2), the object returned from foo() is an rvalue.

In (3), bar() returns a reference so there are no rvalues.

In (4), the temporary std::string object implicitly created from the string literal is an rvalue.

In (5), the temporary X object is an rvalue, so therefore so is the s member.

Expressions such as x+3 typically result in a temporary, which is thus an rvalue. However, if operator overloading has been used to change the return type to a reference, then the result is an lvalue.

Rvalue & Lvalue

Before Explaining This two notation let's Check what is Called Movable and Identity

Identity :- In short anything that has name & we can point to or Reference to know that whether it is same value or Different Value

Moving :- In short anything whose content can be moved from one place or Memory to Other

Lvalue are those value that has Identity so we can point to it or Reference it, but cannot Move it These are called Classical Values

Rvalue are one that are movable (whether has identity or not) these contains temporary values or ADT that support move

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM