6

此类是否设计了标准 C++0x 方法来防止复制分配,以保护客户端代码免受意外双重删除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;
  }
};

你注意到了,我在这里定义了新的movemove-assign方法。我是否正确实施了它们?

有什么方法可以 - 使用movemove-assign定义 - 放入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想法只是一个猜测,在这里。

编辑:为了方便读者,我将答案放入示例代码中。

4

2 回答 2

6

您的示例代码看起来大部分是正确的。

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

  2. if(&other!=this)在您的移动赋值运算符中看起来没有必要但无害。

  3. 初始化列表向量构造函数不起作用。这将尝试复制你的DataHolder,你应该得到一个编译时错误。

  4. 带有右值参数的 push_back 和 emplace_back 调用将起作用。那些带有左值参数(使用y)的人会给你编译时错误。

push_back 和 emplace_back 在您使用它们的方式上确实没有区别。emplace_back 用于当您不想在向量之外构造 DataHolder 时,而是传递参数以仅在向量内部构造一个。例如:

// 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;
}
于 2011-04-16T15:41:05.800 回答
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's data,因为那other是不变的。将其更改为 simple DataHolder&&

于 2011-04-16T15:31:20.850 回答