C++编程高阶-右值引用

右值引用(rvalue reference),是C++程序设计语言自C++11标准提出的一类数据类型。用于实现移动语义(move semantic)与完美转发(perfect forwarding)

作为一种追求执行效率的语言,C++在用临时对象或函数返回值给左值对象赋值时的深度拷贝(deep copy)一直受到诟病。考虑到临时对象的生命期仅在表达式中持续,如果把临时对象的内容直接移动(move)给被赋值的左值对象,效率改善将是显著的。这就是移动语义的来源.

与传统的拷贝赋值运算符(copy assignment)成员函数、拷贝构造(copy ctor)成员函数对应,移动语义需要有移动赋值(move assignment)成员函数、移动构造(move ctor)成员函数的实现机制

右值引用就是为了实现移动语义与完美转发所需要而设计出来的新的数据类型。右值引用的实例对应于临时对象;右值引用并区别于左值引用,用作形参时能重载辨识(overload resolution)是调用拷贝语义还是移动语义的函数。

  • lvalue 左值
    左值存放在内存中,有内存地址,可以通过地址访问,比如变量名,指针,引用.

  • prvalue 右值
    prvalue不在内存中,没有内存地址,它们有时只是在寄存器中短暂的存在,有时仅仅只是逻辑上存在,编程人员无法通过地址(变量名,指针或者引用)来访问prvalue

-xvalue
xvalue是接近生命周期末尾的lvalue.编程人员需要显式地进行强制转换std::move(x),告诉编译器x不再访问,std::move(x)表达式的结果是一个xvalue

move常见错误

  • 忘了move
class Test{
public:
	explicit Test(string&& val)noexcept{
		value_1_ = val;
		value_2_ = move(val);//这里的move不能忘了,在传参时转成了右值,但是在函数内部,变成了左值(它有名字可以调用了)
	}
private:
value_1_;
value_2_;
};
  • move const对象
    move本质上是一个static_cast
    move是具有破坏性,当你move一个对象时,就表明你要更改这个对象(丢弃它),而去move一个const对象这和初衷也不符合.
class Test{
public:
 explicit Test(const string& t){}
 explicit Test(string&& t){}
};
const string s="hahah";
Test t(move(s));

此时的move是无效的,因为s是个const变量,当使用move,const string&&类型,此时没有直接匹配的,编译器将其强制变为const string&最终调用第一个构造函数构造.

  • move一个无效的对象

move的效果取决于对象movr构造函数的实现.
比如:

int i_1=100;
int i_2=move(i_1);//其效果就是i_2=i_1,i_1的值不变.
//对于shared_ptr对象
shared_ptr<int> pt1=make_shared<int>(100);
shared_ptr<int> pt2=move(pt1);
//其效果是pt2或的pt1所指的对象,pt1指向空
//对于string对象
string str1="hahah"
string str2=move(str1);
//其效果就是相当于s1和s2交换,str2并不一定指向空
  • move同类型的局部变量
string foo(){
string s="hahah";
	return move(s);
}

string foo(string s){
	return move(s);
}

两次move都是没必要的,因为对于函数返回局部变量而且类型和返回值类型一致的,编译器自动完成优化了(RVO或者NRVO)
具体可看上一篇文章C++编译器RVO

  • 忘了move不同类型的返回值
shared_ptr<const string> foo(){
	auto p = make_shared<string>("hahahh");
	return move(p);
}
shared_ptr<const string> foo(shared_ptr<string> p){
	return move(p);
}

上面的move是必要的,如果没有move,引用计数加1再减1;
move后,引用计数不会发生变化

move操作带来的问题.

如果一个函数想接受两个string类型的参数,它得写四个函数:

void process(const string& str1,const string& str2);
void process(const string& str1,string&& str2);
void process(string&& str1,const string& str2);
void process(string&& st1,string&& str2);

如果想接受3个,或者4个参数的话,它岂不是得写6个,24个?
如何解决这一问题?
请待下回分解,C++之完美转发

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值