旧标准下移动一个对象需要调用类的拷贝构造函数,如下面的代码:

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的移动构造函数。