将不可复制的对象放入std容器中

时间:2011-04-16 15:25:35

标签: c++ stl c++11 rvalue-reference noncopyable

此类是否设计了标准的C ++ 0x方法来阻止 copy assign ,以保护客户端代码免于意外双重删除data

struct DataHolder {
  int *data;   // dangerous resource
  DataHolder(const char* fn); // load from file or so
  DataHolder(const char* fn, size_t len); // *from answers: added*
  ~DataHolder() { delete[] data; }

  // prevent copy, to prevent double-deletion
  DataHolder(const DataHolder&) = delete;
  DataHolder& operator=(const DataHolder&) = delete;

  // enable stealing
  DataHolder(DataHolder &&other) {
    data=other.data; other.data=nullptr;
  }
  DataHolder& operator=(DataHolder &&other) {
    if(&other!=this) { data = other.data; other.data=nullptr};
    return *this;
  }
};

您注意到,我在此处定义了新的移动移动分配方法。我是否正确实施了它们?

我有什么方法 - 使用移动移动 - 分配定义 - 将DataHolder放入标准容器中?像vector?我该怎么做?

我想知道,有些选择会浮现在脑海中:

// init-list. do they copy? or do they move?
// *from answers: compile-error, init-list is const, can nor move from there*
vector<DataHolder> abc { DataHolder("a"), DataHolder("b"), DataHolder("c") };

// pushing temp-objects.
vector<DataHolder> xyz;
xyz.push_back( DataHolder("x") );
// *from answers: emplace uses perfect argument forwarding*
xyz.emplace_back( "z", 1 );

// pushing a regular object, probably copies, right?
DataHolder y("y");
xyz.push_back( y ); // *from anwers: this copies, thus compile error.*

// pushing a regular object, explicit stealing?
xyz.push_back( move(y) );

// or is this what emplace is for?
xyz.emplace_back( y ); // *from answers: works, but nonsense here*

emplace_back这个想法只是猜测,在这里。

编辑:为了方便读者,我将答案用于示例代码。

2 个答案:

答案 0 :(得分:6)

您的示例代码看起来主要是正确。

  1. const DataHolder &&other(在两个地方)。

  2. 您的移动分配操作符中的
  3. if(&other!=this)看起来不必要但无害。

  4. 初始化列表向量构造函数不起作用。这将尝试复制您的DataHolder,并且您应该收到编译时错误。

  5. 使用rvalue参数的push_back和emplace_back调用将起作用。具有左值参数的那些(使用y)将给出编译时错误。

  6. push_back和emplace_back在使用它们方面确实没有区别。 emplace_back用于当你不想在向量之外构造DataHolder时,而是传递参数以仅在向量内构造一个。 E.g:

    // Imagine this new constructor:
    DataHolder(const char* fn, size_t len);
    
    xyz.emplace_back( "data", 4 );  // ok
    xyz.push_back("data", 4 );  // compile time error
    

    <强>更新

    我刚注意到你的移动赋值操作符中有内存泄漏。

    DataHolder& operator=(DataHolder &&other)
    {
       if(&other!=this)
       {
          delete[] data;  // insert this
          data = other.data;
          other.data=nullptr;
       }
       return *this;
    }
    

答案 1 :(得分:1)

没有名字的临时对象,例如。 DataHolder("a")会在可用时移动。 C ++ 0x中的标准容器将尽可能地移动,这也是允许std::unique_ptr放入标准容器的内容。
除此之外,您实施了错误的移动操作:

  // enable stealing
  DataHolder(const DataHolder &&other) {
    data=other.data; other.data=nullptr;
  }
  DataHolder& operator=(const DataHolder&&other) {
    if(&other!=this) { data = other.data; other.data=nullptr};
    return *this;
  }

你如何从一个恒定的物体移动?您不能只更改other的{​​{1}},因为data是常量。将其更改为简单other