条款25:针对右值引用实施std::move,针对万能引用实施std::foraward

右值引用仅会绑定到那些可移动的对象上(临时对象)

class Widget {
public:
    Widget(Widget && rhs) : name(rhs.name), p(std::move(rhs.p)) {}; // 移动构造函数
private:
    string name;
    shared_ptr<int> p;
};

万能引用只有在使用右值初始化时候才会强制转换成右值类型,正好是std::forward作用

class Widget {
public:
	template<typename T>
	void setName(T &&newName) {
		name = std::forward<T>(newName); // newName是个万能引用
	}
//...	
};

需要避免针对右值引用实施std::forward,也要避免针对万能引用使用std::move

class Widget {
public:
	template<typename T>
	void setName(T&& newName){
		name = std::move(newName); //万能引用,可以编译,但是糟糕透顶
	}
private:
	std::string name;
	std::share_ptr<SomeDataStructure> p;
};

std::string getWidgetName(); // 工厂函数
Widget w;
auto n = getWidgetName();	// n为局部变量
w.setName(n);				// 將n移入w!,n的值未知

局部变量n被传递给w.setName,而调用者会合情合理地假定这是一个对n的只读操作。但由于setName函数内部使用了std::move把它的引用形参无条件的强制转换到右值,n的值就会被移入w.name。这么一来调用完毕setName后,n將变成一个不确定的值

你可能会说setName不应该將形参声明为一个万能引用,因为万能引用不能带有const饰词,你可能会为setName写出常量左值和右值的不同的重载:

class Widget {
public:
    void setName(const std::string &newName){
        name = newName;
    }

    void setName(const std::string &&newName){
        name = std::move(newName);
    }
private:
    std::string name;
    std::shared_ptr<int> p;
};

有两个缺点:

  1. 需要编写和维护更多的代码
  2. 效率打折扣,会执行一次std::string构造函数(以创建临时对象),一次std::string移动赋值运算符(以移动newNamew.name),还有一次string析构函数(以销毁临时变量)

在按值返回的函数中,如果返回的是绑定到一个右值引用或者万能引用的对象,则当你返回该引用时候,应该对其实施std::move或则std::forward:

Matrix operator+(Matrix &&lhs, const Matrix &rhs) {
	lhs += rhs;
	return std::move(lhs);	// 將lhs移入返回值
}

Matrix operator+(Matrix &&lhs, const Matrix &rhs) {
	lhs += rhs;
	return lhs;	// 將lhs复制入返回值
}

lhs为左值会强迫编译器將其复制入返回值存储位置,假定Matrix类型支持移动构造,这將币复制构造效率更高,从而在返回语句中使用std::move会产生更高效的代码

某局部对象可能适用于返回值优化,则请勿针对其实施std::movestd::forward

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值