6

我目前正在尝试弄清楚如何使用包含指向已分配内存的指针的对象正确移动语义。我有一个大数据结构,其中包含一个指向实际存储的内部原始指针(出于效率原因)。现在我添加了一个 move 构造函数和 move 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;
}

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

4

1 回答 1

18

“移动”一个指针与复制一个指针没有什么不同,并且不会将移动的值设置为空(“移动”在这里用引号引起来,因为std::move它实际上并没有移动任何东西,它只是改变了参数的值类别)。只需复制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
}

更好的是,使用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;
}

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

于 2012-01-26T22:32:00.977 回答