有人可以向R-Value解释或指出某种解释吗?我不确定它是什么,我的项目必须加入它。下面是R-Value的演示(第一部分是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;
}
“有人可以向R-Value解释或指出某种解释吗?我不确定它是什么”
术语“左值”最初指的是可能是赋值左侧的表达式。相应地,一个右值(虽然我记得那个术语没有被C89标准使用),但最初恰恰相反:一个表达式不能作为任务的左手边,但这只能是右手边。
C ++ 11通过添加几个细微的术语来解决这个问题,但让我们专注于C ++ 03的含义。
例如,如果你有
int x;
赋值x = 42
没问题,所以x
是一个左值表达式。
作为一个反例,分配x+0 = 42
不行,所以x+0
是一个右值表达式。
表达式2+2
也是如此,它是一个右值表达式。
因此,如果要求您的程序应包含右值,那么只需编写2+2
或者例如(更高级)6*7
,在main
。
原始C没有const
。在C ++中,使用const
,您必须忽略const
,以便将表达式指定为左值或右值。关键点是表达保证是否指向内存中的对象,具有地址的对象:如果是,则表达式是左值。
引用类型意味着左值,因为引用类型的表达式必然是指具有存储器地址的对象,即该表达式是左值。
但是,除了引用之外,type和lvalue / rvalue之间没有任何关联。例如,x
和x+0
都是int
类型的表达式,它们产生相同的int
值。但前者是左值表达式,而后者是右值表达式。
作为一般规则,如果您可以应用内置地址运算符,那么它是一个左值表达式,否则它是一个右值表达式。
rvalue这个术语源于它的历史背景 - 它只能在任务的右侧进行,而不是可以在赋值的左侧进行的左值。因此,命名变量(例如x
)是左值,但是字面整数(例如42
)是右值。
然而,在现代C ++中,它比那更细致。
在C ++中,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
对象是右值。
在(2)中,从foo()
返回的对象是右值。
在(3)中,bar()
返回一个引用,因此没有rvalues。
在(4)中,从字符串文字隐式创建的临时std::string
对象是右值。
在(5)中,临时X
对象是右值,因此s
成员也是如此。
像x+3
这样的表达式通常会导致临时性,因此是一个rvalue。但是,如果已使用运算符重载将返回类型更改为引用,则结果为左值。