使用C++11移动复制
来源:互联网 发布:凸优化数学基础 编辑:程序博客网 时间:2024/06/05 04:15
以下代码来源于《深入实践Boost:Boost程序库开发的94个秘笈》一书
制作一个可移植的使用右值引用的类
C++11标准的最大功能之一是右值引用。此功能允许修改临时对象,从它们那里“偷”资源。在C++03中没有有值引用,但使用Boost.Move库,可以写一些可移植的使用右值引用的代码。
左值:一个函数或者对象实例。
失效值:生命期即将结束的对象。
广义左值:包括左值和失效值。
右值:包括失效值、临时对象、以及不关联对象的值。
纯右值:非失效值的那些右值。
左右值鉴别最简单的办法:左值可以用取地址操作符”&“获取地址,右值无法使用”&“。
例如:
int x = 0; //对象实例,有名,x是左值int* p = &++x; //可以取地址,++x是左值++x = 10; //前置++返回的是左值,可以赋值p = &x++; //后置++操作返回一个临时对象,不能取地址或赋值,是右值,编译错误
使用方法步骤:
- 把宏BOOST_COPYABLE_AND_MOVABLE(classname)放置在类的private节中
- 保留一个正常的拷贝构造函数
- 编写一个复制赋值函数,参数为BOOST_COPY_ASSIGN_REF(classname)
- 编写一个移动构造函数和一个移动赋值函数,参数为BOOST_RV_REF(classname)
#include <iostream>#include <string>#include <boost/variant.hpp>#include <boost/swap.hpp>using namespace std;namespace other { class characteristics {};}struct person_info {private: // 这个宏声明person_info是一个可复制和可移植的类 // 必须要实现一个移动构造函数和拷贝赋值函数 BOOST_COPYABLE_AND_MOVABLE(person_info)public: bool is_male_; std::string name_; std::string second_name_; other::characteristics characteristic_; // person_info 的默认构造函数和swap调用是非常快 / 廉价 person_info() {} person_info(const person_info& p) :is_male_(p.is_male_) ,name_(p.name_) ,second_name_(p.second_name_) ,characteristic_(p.characteristic_) {} // Move constructot 移动构造函数 person_info(BOOST_RV_REF(person_info) person) { swap(person); } // Move assignment 移动赋值函数 person_info& operator=(BOOST_RV_REF(person_info) person) { if (this != &person) { swap(person); person_info tmp; tmp.swap(person); } return *this; } // Copy assignment 复制赋值函数 person_info& operator=(BOOST_COPY_ASSIGN_REF(person_info) person) { if (this != &person) { person_info tmp(person); swap(tmp); } return *this; } void swap(person_info& rhs) { std::swap(is_male_, rhs.is_male_); //必须显示调用std域的swap,否则报错 name_.swap(rhs.name_); second_name_.swap(rhs.second_name_); boost::swap(characteristic_, rhs.characteristic_); }};int main(){ person_info vasya; vasya.name_ = "Vasya"; vasya.second_name_ = "Snow"; vasya.is_male_ = true; person_info new_vasya(boost::move(vasya)); assert(new_vasya.name_ == "Vasya"); assert(new_vasya.second_name_ == "Snow"); assert(vasya.name_.empty()); assert(vasya.second_name_.empty()); vasya = boost::move(new_vasya); assert(vasya.name_ == "Vasya"); assert(vasya.second_name_ == "Snow"); assert(new_vasya.name_.empty()); assert(new_vasya.second_name_.empty()); return 0;}
制作一个不可复制的类
为一个类提供一个复制构造函数和移动赋值运算符将需要太多的工作,或因技术原因一个类拥有一些绝对不可复制的资源:
例如,下面的例子:
class descriptor_owner{ void* descriptor_;public: explicit descriptor_owner(const char* params) { descriptor_ = (void*)params; } ~descriptor_owner() { system_api_free_descriptor(descriptor_); }};int main(){ descriptor_owner d1("O_o"); descriptor_owner d2("^_^"); // d2的描述符未正确释放 d2 = d1; // d2的析构函数将释放描述符 // d1的析构函数将尝试释放已经释放的描述符 return 0;}
boost::noncopyable可以避免这种情况,如果从它派生出你自己的类,C++编译器将不会产生复制构造函数和赋值运算符:
#include <boost/noncopyable.hpp>class descriptor_owner_fixed : private boost::noncopyable{ void* descriptor_;public: explicit descriptor_owner_fixed(const char* params) { descriptor_ = (void*)params; } ~descriptor_owner_fixed() { system_api_free_descriptor(descriptor_); }};int main(){ descriptor_owner_fixed d1("O_o"); descriptor_owner_fixed d2("^_^"); // 将无法编译 d2 = d1; // 也无法编译 descriptor_owner_fixed d3(d1); return 0;}
当然,我们可以使descriptor_owner_fixed的复制构造函数和赋值运算符私有,或者只定义它们而没有实现,也可以实现相同的结果。boost::noncopyable类目前正是这么实现。
制作一个不可复制但可移动的类
C++11提供了只可移动的(move-only)类(比如std::unique_ptr或std::thread)。采用这样的方法,可以做一个只可移动的descriptor_owner类:
class descriptor_owner1 : private boost::noncopyable{ void* descriptor_;public: descriptor_owner1() : descriptor_(NULL) {} explicit descriptor_owner1(const char* params) : descriptor_(_strdup(params)) {} descriptor_owner1(descriptor_owner1&& param) : descriptor_(param.descriptor_) { param.descriptor_ = NULL; } descriptor_owner1& operator=(descriptor_owner1&& param) { clear(); std::swap(descriptor_, param.descriptor_); return *this; } void clear() { free(descriptor_); descriptor_ = NULL; } bool empty() const { return !descriptor_; } ~descriptor_owner1() { clear(); cout << "~descriptor call" << endl; }};descriptor_owner1 construct_descriptor2(){ return descriptor_owner1("Construct using this string");}void foo_rv(){ cout << "C++11" << endl; descriptor_owner1 desc; desc = construct_descriptor2(); assert(!desc.empty());}int main(){ foo_rv(); system("pause"); return 0;}
以上只能在C++11兼容编译器中工作。下面修改这个例子以便可用于C++03编译器。
使用方法步骤:
- 将BOOST_MOVEABLE_BUT_NOT_COPYABLE(classname)宏放置再private节。
- 编写一个移动构造函数和一个移动赋值函数,参数为BOOST_RV_REF(classname)。
#include <boost/move/move.hpp>#include <boost/container/vector.hpp>class descriptor_owner_movable{ void* descriptor_; BOOST_MOVABLE_BUT_NOT_COPYABLE(descriptor_owner_movable)public: descriptor_owner_movable() : descriptor_(NULL) {} explicit descriptor_owner_movable(const char* param) :descriptor_(_strdup(param)) {} descriptor_owner_movable(BOOST_RV_REF(descriptor_owner_movable) param) :descriptor_(param.descriptor_) { param.descriptor_ = NULL; } descriptor_owner_movable& operator=(BOOST_RV_REF(descriptor_owner_movable) param) { clear(); std::swap(descriptor_, param.descriptor_); return *this; } void clear() { free(descriptor_); descriptor_ = NULL; }};descriptor_owner_movable construct_descriptor3(){ return descriptor_owner_movable("Construct using this string");}int main(){ descriptor_owner_movable movable; movable = construct_descriptor3(); boost::container::vector<descriptor_owner_movable> vec; vec.resize(10); vec.push_back(construct_descriptor3()); vec.back() = boost::move(vec.front()); system("pause"); return 0;}
0 0
- 使用C++11移动复制
- Turbo C移动,删除,和复制
- C#:文件创建、复制、移动、删除
- C常用类整理(2)--文件复制、删除、移动
- c语言实现文件移动\复制\重命名\删除:
- C语言文件与目录(五)移动与复制
- 使用SPExport和SPImport复制或移动SharePoint网站
- Vim编辑器如何使用复制、移动及删除操作
- 使用clipboard.js实现移动端粘贴复制
- 记一次FTPClient的使用。(复制、删除、移动)
- 【C\C++学习】之十八、C++11六大函数(构造函数,移动构造函数,移动赋值操作符,复制构造函数,赋值操作符,析构函数)
- 文件夹的移动复制
- 复制和移动文件
- 【html】移动端长按复制
- 如何复制移动单元格
- linux移动,复制命令
- centos7 复制移动删除
- 内存移动或复制
- CSS3制作下拉框效果
- 安装Python
- iOS NSException 配套使用方案
- android 头像利用okhttp上传到服务器部分----萌新成长之路
- XCOPY命令参数
- 使用C++11移动复制
- TensorFlow极简教程:创建、保存和恢复机器学习模型
- 矩阵快速幂优化递推式 例:斐波那契数列 poj 3070
- Oracle大表数据导出导入
- js中的数据类转换
- 【JAVA】CentOS7部署Java和Tomcat
- Thread线程
- 站在用户的角度看问题
- 快速理解动态代理模式