编写一个安全可靠的C++11类:引入移动语义
来源:互联网 发布:金山快译怎么汉化软件 编辑:程序博客网 时间:2024/06/11 18:54
右值引用和移动语义
在C++11(即C++0x)中,引入了右值引用的概念,同时在STL中提供std::move函数。这个机制完善了C++中关于左值、右值、以及引用的概念,优雅完美地解决了临时变量效率的问题。另外std::forward实现了所谓的“完美转发”,在泛型编程中有很大的作用。
这篇文章,只对右值引用和移动语义做几个简单的实践。
测试代码
#include <iostream>class Implemention { //演示使用,留空。 //实践中,如果使用PIMPL手法,则通常将其声明在单独的头文件中。};class Interface {public: void test() { std::cout << "test" << std::endl; } Interface() { std::cout << "constructor" << std::endl; m_pImpl = nullptr; } ~Interface() { std::cout << "destructor" << std::endl; //无须 if(m_pImpl == nullptr) 判断,因为delete nullptr;合法 delete m_pImpl; } Interface(const Interface &a) { std::cout << "copy constructor" << std::endl; m_pImpl = new Implemention(*a.m_pImpl); //调用class Impl的copy-assignment函数 } Interface(Interface &&a) { std::cout << "move constructor" << std::endl; m_pImpl = nullptr; swap(a); } Interface & operator=(const Interface &a) { std::cout << "copy assignment" << std::endl; //证同测试:如果后续语句能保证“自我赋值”不出故障,则可以考虑省略“证同测试”。 //如果对象相同,那么提高了效率,否则降低了效率,需要综合考虑。 //详见《Effective C++》条款11 if(this == &a) return *this; Interface tmp(a); swap(tmp); return *this; } Interface & operator=(Interface &&a) { std::cout << "move assignment" << std::endl; //证同测试:说明同上 if(this == &a) return *this; m_pImpl = nullptr; swap(a); return *this; } void swap(Interface &a) throw() { //保证无异常 //针对m_p的类型(在此为指针),优先使用专属swap,其次std::swap特化版本,最次使用std::swap //详见《Effective C++》条款25 using std::swap; swap(m_pImpl, a.m_pImpl); }private: Implemention * m_pImpl;};//在class A的同属命名空间中,定义专属swapvoid swap(Interface & lh, Interface & rh){ lh.swap(rh);}//std::swap特化版本namespace std {template<>void swap<Interface>(Interface & lh, Interface & rh) { lh.swap(rh);}}//返回临时对象时,依旧按照之前的写法,让编译器做优化,而非返回右值引用,这样可以提高兼容性。//编译器会优先使用移动语义,其次使用RVO,最后才会copy-assignment。Interface return_local(){ Interface var; return var;}//在返回临时对象的成员时,因为此时编译器不会做其他优化,所以需要显式指定返回右值引用。Interface && return_local_member(){ struct{ Interface m; }tmp; return std::move(tmp.m);}int main(int, char *[]){ //constructor Interface a; std::cout << "-------a----------" << std::endl; Interface b(Interface()); //不合法的写法,被编译器警告并忽略 std::cout << "-------b-----------" << std::endl; //copy constructor Interface c(a); std::cout << "-------c----------" << std::endl; Interface d(Interface(a)); //不合法的写法,被编译器警告并忽略 std::cout << "-------d-----------" << std::endl; Interface e = a; std::cout << "-------e----------" << std::endl; Interface f = Interface(a); //不产生临时对象,直接被优化为与e相同 std::cout << "-------f----------" << std::endl; //copy assignment Interface g; g = a; std::cout << "-------g----------" << std::endl; //move constructor Interface h(std::move(Interface())); //产生临时对象 std::cout << "-------h----------" << std::endl; Interface i(std::move(Interface(a))); //产生临时对象 std::cout << "-------i----------" << std::endl; Interface j(std::move(a)); //保证此后不再使用a std::cout << "-------j----------" << std::endl; Interface k = std::move(a); //与j相同 std::cout << "-------k----------" << std::endl; //move assignment Interface l; l = std::move(Interface()); //产生临时对象 std::cout << "-------l----------" << std::endl; Interface m; m = std::move(Interface(a)); //产生临时对象 std::cout << "-------m----------" << std::endl; Interface n; n = std::move(a); //保证此后不再使用a std::cout << "-------n----------" << std::endl; //return local Interface o = return_local(); std::cout << "-------o----------" << std::endl; Interface p = return_local_member(); std::cout << "-------p----------" << std::endl; a;b;c;d;e;f;g;h;i;j;k;l;m;n;o;p; //使用上述变量,避免编译警告 return 0;}
上述代码运行结果
Starting D:\QtProjects\build-move-Desktop_Qt_5_7_1_MSVC2013_64bit-Debug\debug\move.exe...constructor-------a-----------------b-----------copy constructor-------c-----------------d-----------copy constructor-------e----------copy constructor-------f----------constructorcopy assignmentcopy constructordestructor-------g----------constructormove constructordestructor-------h----------copy constructormove constructordestructor-------i----------move constructor-------j----------move constructor-------k----------constructorconstructormove assignmentdestructor-------l----------constructorcopy constructormove assignmentdestructor-------m----------constructormove assignment-------n----------constructormove constructordestructor-------o----------constructordestructormove constructor-------p----------destructordestructordestructordestructordestructordestructordestructordestructordestructordestructordestructordestructordestructordestructorD:\QtProjects\build-move-Desktop_Qt_5_7_1_MSVC2013_64bit-Debug\debug\move.exe exited with code 0另外,经过测试,如果上述代码中不定义move-constructor函数,那么编译器会调用copy-constructor函数;同样地,如果不定义move-assignment函数,那么编译器会调用copy-assignment函数。这样C++11就保持了对不支持右值引用的兼容性。
总结
源代码中有许多注释,其中包含了非常多的知识点和编程经验点,参考了一些书和网络资料。
可以看出,规范、高效、安全、高扩展性的代码,是很难写的,需要对细节的准确把握,以及对可靠编程经验的总结和学习。
扩展阅读
C++11 标准新特性: 右值引用与转移语义
c++11 函数内部返回对象使用move语义的最佳实践
RVO V.S. std::move
【编程篇】C++11系列之——临时对象分析
0 0
- 编写一个安全可靠的C++11类:引入移动语义
- 准备一个安全可靠的发布流程
- 如何选择安全可靠质量好的移动电源
- Java篇:编写安全可靠程序的75条建议
- 如何编写一个可靠的linux守护进程
- 如何编写一个可靠的linux守护进程
- 如何编写一个可靠的linux守护进程
- 编写安全的C代码
- C++11:移动语义
- 安全可靠的二甲基吡啶哪有卖
- 安全可靠的硝酸铊到哪买
- 编写可靠的 .NET 代码
- 编写可靠的 .NET 代码
- 发布一个C编写的Ping类
- 如何编写一个安全的read函数
- 数据不落地、移动新应用、安全更可靠
- c#:利用Timer和图片框控件,编写一个图片不断向左移动的小动画
- 编写安全的Symbian C 游戏代码
- 12. Integer to Roman \ 13. Roman to Integer
- 80.NYOJ--STL--一种排序
- Android融云判断是否用户已经加入黑名单和加入&移除黑名单
- 蓝桥杯 - 算法训练 - 寻找数组中最大值 - Java
- C++ 右值引用
- 编写一个安全可靠的C++11类:引入移动语义
- static关键字的用法
- linux访问windows上的共享文件夹
- 解决使用MSBuild编译项目没有拷贝间接引用的dll问题
- JavaScript window.document的属性、方法和事件小结
- 时间复杂度和空间复杂度详解
- string::npos,一个很大的数
- 单例设计模式
- 分布式系统程序编写要点