在成员容器中复制具有仅可移动但可克隆类型的构造函数

Copy constructors with move-only, but cloneable types in member containers

本文关键字:类型 构造函数 可移动 成员 复制      更新时间:2023-10-16

假设我们有两种类型,T1T2

除了以下事实之外,T1并不重要:

  • 它是不可复制的
  • 它有一个move构造函数
  • 我们有一个优秀的函数,签名T1 copy(T1 const& orig),它创建了一个副本

T2可以简化为以下类别:

// T2.h
class T2 {
public:
T2() { /* initializes the vector with something */ }
T2(T2 const& other);
private:
std::vector<T1> v;
}
// T2.cpp
T2::T2(T2 const& other) : ... {}

如果只能写入省略号部分或全局范围,您将如何实现此方法?

一个简单的现实世界用例——假设"你不能在大括号之间写任何东西"部分是现实世界的限制:

  • T1就是std::unique_ptr<anything>
  • copy就是std::make_unique
  • anything有一个复制构造函数

我还有两个额外的实现要求:

  • 性能。它不应该比复制构造函数主体中有for循环的天真实现慢(相当)
  • 可读性。这个问题背后的全部要点是做一些比循环的琐碎更清晰/干净的事情(例如,想象T2有两个或多个成员向量)

可选,但很高兴拥有以下功能:

  • 很容易推广到其他容器的东西
  • 只使用迭代器的东西
  • 一般的东西

澄清:我知道这个问题用std::vector<T1> copy_vec(std::vector<T1> const& orig)全局函数是平凡可解的。将该函数放入T2.cpp中的匿名命名空间也会使其成为本地函数,但我反对它的可读性,我认为它根本不会比for循环更好。如果复制构造函数不在实现文件中,而是内联在头中,那么这显然是一个糟糕的解决方案。

因此,我的问题的措辞是:

  • 是否已经实现了类似的东西,我可以将其包括在内
  • 如果没有,为什么?我并不是说我考虑了每一个角落的情况,但我认为这是一种可能以良好的通用方式实现的东西,多亏了unique_ptr,这是一个足够常见的情况

天真循环没有错:

v.reserve(other.v.size());
for (auto& elem : other.v) {
v.push_back(copy(elem));
}

这是可读性很强的,也是最佳的。

虽然我想现代,聪明的解决方案是使用范围-v3:

T2(T2 const& other)
: v(other.v | view::transform(copy))
{ } 

我不确定这是否比循环更好来证明额外的复杂性,但YMMV。