C++11新特性:对象移动
旧标准下移动一个对象需要调用类的拷贝构造函数,如下面的代码:
class HasPtr
{
public:
HasPtr(const HasPtr& p):
ps(new std::string(p.ps)),i(p.i){ }
//其他成员函数
private:
std::string* ps;
int i;
};
如果要将一个容器A里的对象转移到另一个容器B,则必须将A里的元素挨个拷贝到B里面,然后销毁A里的元素:
vector<HasPtr> A,B;
//给A容器填充各个元素的代码
for(auto a : A)
{
B.push_back(HasPtr(a));//调用类的拷贝构造函数
}
A.clear();//析构A中所有元素
以上过程需要重新为每个元素分配空间,然后释放原空间,做了很多不必要的操作,影响了程序的性能。 在新标准下,引入了两种机制避免对象移动时的拷贝: * std::move * 移动构造函数 以下对这两种机制进行详细说明: * std::move是新标准库函数,定义在头文件utility中,关于std::move的实现细节暂且不谈,现在只要知道它的作用就是将一个左值或者右值转换为一个右值:
int i = 42;
int &&rr = i; //错误,不能将一个右值引用绑定到一个一个左值上
int &&rr = std::move(i); //正确,std::move将左值转换为一个右值
int &&rr2 = rr; //错误,rr是左值
int &&rr2 = std::move(rr); //正确
- 移动构造函数类似于拷贝构造函数,只是它不是从给定对象拷贝资源而是“窃取”资源。可以给HasPtr定义它自己的移动构造函数:
HasPtr::HasPtr(HasPtr &&s) noexcept :i(s.i),ps(s.ps) { s.ps = nullptr; //“放弃s.ps指向的资源的管理权限,彻底交给新对象接管 }
通过上面的过程,原对象s所管理的资源移交给了新对象,并且原对象的ps指针被置为nullptr,这样原对象就可以放心地被析构(或者是被重新使用)而不会影响它原本所管理的资源。 结合以上两种机制,我们便可以写出移动对象的代码: ```C++ vector
A,B; //给A容器填充各个元素的代码
for(auto a : A) { B.push_back(HasPtr(std::move(a));//调用类的移动构造函数 } A.clear(); //调用析构函数,安全析构原对象 ``` std::move(a)返回一个右值引用,与HasPtr(HasPtr &&)即HasPtr的移动构造函数精确匹配,因此会调用HasPtr的移动构造函数。