提供正确的移动语义

LiK*_*Kao 3 c++ rvalue-reference move-semantics c++11

我目前正试图弄清楚如何使用包含指向已分配内存的指针的对象正确地移动语义.我有一个大的数据结构,其中包含一个指向实际存储的内部原始指针(出于效率原因).现在我添加了一个移动构造函数并移动operator=().在这些方法中,我是std::move()指向新结构的指针.但是我不知道如何处理来自其他结构的指针.

这是我正在做的一个简单的例子:

class big_and_complicated {
   // lots of complicated code
};

class structure {
public:
   structure() :
      m_data( new big_and_complicated() )
   {}

   structure( structure && rhs ) :
      m_data( std::move( rhs.m_data ) )
   {
      // Maybe do something to rhs here?
   }

   ~structure()
   {
      delete m_data;
   }

private:
   big_and_complicated * m_data;
}

int main() {
  structure s1;
  structure s2( std::move( s1 ) );
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在从我的理解,std::move( s1 )s2唯一可以安全做的事情就是s1调用它的构造函数.但是据我所知,这将导致删除s1析构函数中包含的指针,使得渲染s2无用.所以我猜我必须做一些事情来使析构函数std::move()在指针时安全.据我所知,这里最安全的做法是将它设置0为移动的对象,因为这会在以后delete变成无操作.到目前为止,这种推理是否正确?或者std::move()实际上足够聪明,可以为我指出指针,使其使用安全吗?到目前为止,我看到实际测试套件中没有崩溃,但我还没确定实际调用了move-constructor.

ild*_*arn 13

"移动"指针与复制指针没有什么不同,并且没有std::movemove -from值设置为null('moving'在这里是引号,因为实际上没有移动任何东西,它只是改变了参数的值类别).只需复制rhs'指针然后将其设置为nullptr:

struct structure
{
    structure()
      : m_data{new big_and_complicated{}}
    { }

    structure(structure&& rhs)
      : m_data{rhs.m_data}
    {
        rhs.m_data = nullptr;
    }

    structure& operator =(structure&& rhs)
    {
        if (this != &rhs)
        {
            delete m_data;
            m_data = rhs.m_data;
            rhs.m_data = nullptr;
        }
        return *this;
    }

    ~structure()
    {
        delete m_data;
    }

private:
    big_and_complicated* m_data;

    structure(structure const&) = delete;             // for exposition only
    structure& operator =(structure const&) = delete; // for exposition only
}
Run Code Online (Sandbox Code Playgroud)

更好的是,使用std::unique_ptr<big_and_complicated>而不是,big_and_complicated*你不需要自己定义任何一个:

#include <memory>

struct structure
{
    structure()
      : m_data{new big_and_complicated{}}
    { }

private:
    std::unique_ptr<big_and_complicated> m_data;
}
Run Code Online (Sandbox Code Playgroud)

最后,除非你真的想要structure保持不可复制,否则你最好只在内部实现正确的移动语义big_and_complicated并直接structure持有一个big_and_complicated对象.

  • 您的移动赋值运算符在移动赋值之前将内存"this-> m_data"指向泄漏.我偶尔会对这个错误感到内疚.:-) (2认同)