删除第 3 方类的复制者

Ben*_*ler 7 c++

我有一个类存储一个大的std::map. 我的理解是,执行此操作的惯用方法是:

class Foo {
 public:
  Foo(/* Note: passed by value */ std::map<Bar, Baz> large_map) : large_map_(std::move(large_map)) {}
 private:
  std::map<Bar, Baz> large_map_;
};

int main() {
  std::map<Bar, Baz> large_map;
  // Work hard to initialize large_map.
  Foo foo = Foo(std::move(large_map));
}
Run Code Online (Sandbox Code Playgroud)

这会将 large_map 的所有权从 main 转移到构造函数 arg,然后转移到 Foo 的成员。问题是代码很难正确使用,我发现有人在某个地方创建了 aFoo并忘记将地图移动到 ctor 中:

void deep_dark_hidden_code() {
  std::map<Bar, Baz> large_map;
  // Work hard to initialize large_map.
  Foo foo = Foo(large_map); // Whoops! The author of this code forgot to std::move
}
Run Code Online (Sandbox Code Playgroud)

Foo我正在寻找一种可以防止此类错误的写作方法。我的第一个想法是使用unique_ptr

class Foo {
 public:
  Foo(std::unique_ptr<std::map<Bar, Baz>> large_map_ptr) : large_map_(std::move(*large_map_ptr)) {}
 private:
  std::map<Bar, Baz> large_map_;
};

int main() {
  std::unique_ptr<std::map<Bar, Baz>> large_map_ptr = new std::map<Bar, Baz>;
  // Work hard to initialize large_map_ptr.
  Foo foo = Foo(std::move(large_map_ptr));
}
Run Code Online (Sandbox Code Playgroud)

这段代码本质上是用作unique_ptr擦除std::map. 我的问题是是否有更明确的方法来做到这一点。一些神奇的模板,make_uncopyable例如:

class Foo {
 public:
  Foo(make_uncopyable<std::map<Bar, Baz>> large_map) : large_map_(std::move(large_map)) {}
 private:
  std::map<Bar, Baz> large_map_;
};
Run Code Online (Sandbox Code Playgroud)

期望的效果是保持代码完整main,但阻止代码deep_dark_hidden_code编译。

Cha*_*onX 1

这里的标题似乎有点用词不当(或者至少与您的问题的内容不一致):

(至少在给出的示例中),您不想删除复制构造函数 ie Foo::Foo(const Foo& other),而是防止Foo使用不可移动参数调用 's 构造函数。

正如Mestkon指出的那样(这一切都归功于他们 - 如果他们想将其发布为答案,只需大喊一声,我就会删除我的),您可以更改 的Foo构造函数以需要std::map<Bar, Baz>&& large_mapie

Foo(std::map<Bar, Baz>&& large_map) : large_map_(std::move(large_map)) {}
Run Code Online (Sandbox Code Playgroud)

Godbolt 的测试证实编译器将拒绝接受Foo foo = Foo(large_map);中的deep_dark_hidden_code().,要求参数可移动(根据需要)。这可能仍然存在其他人“修复”他们的代码的风险,只需简单地在std::move()他们的周围打上 a large_map,然后在用它构建Foo尝试继续使用它。

如果您确实想阻止复制构造函数的调用(此处std::map),事情会变得相当困难,因为您无法更改 std::map 的定义来删除其复制构造函数。我觉得我对此没有一个好的答案。