设为首页 加入收藏

TOP

8.8 完美转发(1)
2013-10-07 16:08:53 来源: 作者: 【 】 浏览:62
Tags:8.8 完美 转发

8.8  完美转发(1)

完美转发是一个重要的概念,因为它能显著提升大对象的性能,这些大对象会花很多时间进行复制或创建。完美转发仅与类模板或函数模板的环境相关。初看起来它似乎有点复杂,但一旦掌握了这个概念,它就会变得非常简单。那么什么是完美转发呢?

假定有一个函数fun1(),它用一个类类型T来参数化。这可以用一个函数模板来定义,或者在类模板中定义。再假定将fun1()定义为带一个T&&类型的rvalue引用形参。如第6章所述,fun1()可以用一个lvalue、lvalue引用或rvalue实参来调用。Lvalue或lvalue引用实参会使fun1()模板实例有一个lvalue引用形参,否则它就有一个rvalue引用形参。

接着假定fun1()调用了另一个函数fun2(),fun2()有两个版本,一个版本有一个lvalue引用形参,另一个版本有一个rvalue引用形参。fun1()把它接收的实参传送给fun2()。理想情况下,当fun1()接收的实参是一个rvalue引用时,它就应调用有rvalue引用形参的fun2()版本,这样初始参数就不会移动或复制。当实例化fun1()并用lvalue或lvalue引用实参调用时,它就应调用有lvalue引用形参的fun2()版本。换言之,fun1()的实参要进行完美转发使代码总保持最佳性能。

当实参是rvalue时,需要将fun1()中的形参引用从lvalue转换为rvalue的方式,这样就可以把它作为rvalue传送给fun2()。于是该实参就不会复制或移动。fun1()的实参是lvalue或lvalue引用时,它就应保持不变,就像在对fun2()的调用中一样。这就是utility头文件中声明的std::forward()函数模板的作用。如果给它传送一个rvalue引用实参,它就把该实参返回为rvalue。如果给它传送一个lvalue引用,它就把该实参返回为一个lvalue引用。下面看看其工作方式。

试一试:完美转发

这个例子使用本章末尾详细讨论的string类。除了演示完美转发之外,该例子还演示了如何把模板函数定义为非模板类的一个成员,以及如何使用带两个类型形参的模板。该示例定义的Person类如下所示:
 

  1. class Person  
  2. {  
  3. public:  
  4. // Constructor template  
  5. template<class T1, class T2> 
  6. Person(T1&& first, T2&& second) :  
  7. firstname(forward<T1>(first)), secondname(forward<T2>(second)) {}  
  8. //                  firstname(first), secondname(second) {}  
  9. string getName() const  
  10. {  
  11. return firstname.getName() + " " + secondname.getName();  
  12. }  
  13. private:  
  14. Name firstname;  
  15. Name secondname;  
  16. };  

这是一个普通的类,其构造函数由一个带两个类型形参T1和T2的模板来定义,这样构造函数的实参就可以是不同的类型,例如string类型和char*类型。存储一个人的姓名的数据成员是Name类型,这将稍后定义。Person构造函数用实参初始化数据成员之前,把它们传送给utility头文件中的std::forward()。这将确保rvalue引用实参用于初始化Person类的数据成员时仍是rvalue引用。后面会注释掉这一行代码。getName()成员返回Person对象的字符串表示。

下面是Name类的定义:

  1. class Name  
  2. {  
  3. public:  
  4. Name(string& aName) : name(aName)  
  5. {  
  6. cout << "Lvalue Name constructor." << endl;  
  7. }  
  8. Name(string&& aName) : name(move(aName))  
  9. {  
  10. cout << "Rvalue Name constructor." << endl;  
  11. }  
  12. const string& getName() const { return name; }  
  13. private:  
  14. string name;  
  15. };  

这个类把一个名字封装为一个string对象。string对象可以从以空字符结尾的字符串或另一个string对象中创建。该类有两个构造函数,一个带lvalue引用实参,另一个带rvalue引用实参,后者仅在实参是rvalue引用时调用。移动rvalue引用实参的原因是string类支持移动语义。

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇8.7.4 函数对象模板 下一篇8.8 完美转发(2)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·python数据分析岗的 (2025-12-25 10:02:21)
·python做数据分析需 (2025-12-25 10:02:19)
·成为一个优秀的pytho (2025-12-25 10:02:16)
·Java后端面试实习自 (2025-12-25 09:24:21)
·Java LTS版本有哪些 (2025-12-25 09:24:18)