《Effective Modern C++》学习笔记 - Item 25: 对右值引用参数使用std::move,对万能引用参数使用std::forward

本文探讨了在C++中如何正确使用std::move和std::forward。对于右值引用参数,应在最后一次使用时使用std::move;对于万能引用参数,推荐使用std::forward以防止意外左值转右值。同时,返回值为按值返回的函数,应使用std::move或std::forward优化返回过程。然而,不应在可以进行返回值优化(RVO)的局部变量上使用std::move,以免影响性能。理解并恰当应用这些原则对于优化C++代码至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 在函数中,对右值引用的参数使用 std::move,对万能引用的参数使用 std::forward,不能用反:

    • 对右值引用使用 std::forward<T>() 需要额外写一遍类型 T,代码冗余容易出错;
    • 对万能引用使用 std::move 更糟糕,因为万能引用参数可以绑定到左值引用,使用 std::move 可能会错误地破坏传入的左值参数(准确来说,是错误地将其强制转型为右值,导致后续使用时可能被破坏)。
  • 在一个函数中如果要多次使用一个右值/万能引用对象,仅在最后一次对其用 std::movestd::forward

  • 对于一个返回值类型为按值返回(by value)的函数,如果返回的是右值引用或万能引用对象,应该使用 std::movestd::forward,例如:

    Matrix 											// by-value return
    operator+(Matrix&& lhs, const Matrix& rhs)
    {
    	lhs += rhs;
    	return std::move(lhs); 						// move lhs into
    } 												// return value
    

若是写为 return lhs,则会导致 lhs 被拷贝而非移动到返回值,通常开销更大。即使 Matrix 类型暂时不支持移动构造也无妨,此时移动会默认降级为拷贝操作。如果后续 Matrix 支持了移动构造,该函数也会自动从中收益,转换为移动操作。

  • 注意,以上规则适用于函数的右值或万能引用参数,不能扩展到函数的局部变量
Widget makeWidget()
{
	Widget w; 				// local variable
	... 					// configure w
 	return w; 				// "copy" w into return value
 	return std::move(w); 	// move w into return value (don't do this!)
}

上面的 return 语句看起来好像做了一次不必要的从局部变量 w 到返回值的拷贝操作,但实际并非如此。在C++11提出移动语义很久之前,标准委员会就已经注意到这个问题,并提出可以通过直接在函数返回值的内存位置构造 w 避免拷贝,这种技术称为 RVO/NRVO,即(Named) Return Value Optimization,(具名)返回值优化(二者的区别:前者针对 Widget w; return w;,后者针对 return Widget())。该技术的更多细节可以参考《深度探索C++对象模型》第二章。

下面的 return 语句使用 std::move,的确能享受到移动操作的好处;但其返回类型是 w 的引用,导致编译器无法对其使用 RVO 优化。而相比之下,RVO 的性能提升高于移动操作。况且,C++标准还规定:在可以使用 RVO 优化时,即使因某些原因无法实现(例如,函数内有多个 if-else 控制路径返回不同局部变量),编译器也应将返回值视为右值。换言之,上面的 return 语句要么能使用性能更好的优化技术,要么等同于下面的 return 语句。为局部变量添加 std::move 完全是一种画蛇添足的行为。

总结

  1. 在最后一次使用时,对右值引用参数使用 std::move,对万能引用参数使用 std::forward
  2. 如果函数返回类型是按值返回,且返回值是右值或万能引用,也应对其使用 std::movestd::forward
  3. 永远不要在返回语句中对可以进行返回值优化(RVO)的局部变量使用 std::movestd::forward
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值