如何:在没有适当的默认构造函数的情况下复制类的实例;它的成员没有默认构造函数

How to: copying an instance of a class without a proper default constructor; that has members without a default constructor?

本文关键字:构造函数 默认 实例 成员 复制 情况下 如何      更新时间:2023-10-16
// B doesn't have a default constructor.
class A {
  public:
  A(Important resource) : b(resource) {}
  B b;
};

阅读三个规则来找出将类的实例复制到vector中的问题。

所以问题是我们在循环中生成实例:

std::vector<A> some_vector(0);
for (int i = 0; i < 7; i++)
  some_vector.push_back(A(resources[i]));

从我们在Valgrind中看到的情况来看,它看起来像是复制构造函数把事情搞砸了。当我们将代码改为:

std::vector<A*> some_vector(0);
for (int i = 0; i < 7; i++)
  some_vector.push_back(new A(resources[i]));

问题得到缓解。虽然不需要,但我不喜欢这样做。所以我在想,当复制构造函数试图复制一个没有正确默认构造函数的类时,它怎么知道该怎么做?

对于c++中要压入std::vector的T类型元素,

T必须满足CopyAssignable和CopyConstructible的要求。

这意味着它必须有一个工作的移动或复制构造函数,将在创建新对象时使用。它通常不需要默认构造函数,但某些操作可能需要它,例如resize

作为示例中的资源,它应该是不可复制的,但可能是可移动的。如果B没有正确的复制构造函数,你最终会得到一个资源的副本,并且析构函数会多次释放该资源(例如释放内存或关闭文件)。

对于资源,常见的模式是使用RAII,例如std::unique_pointer对于内存。

PS:从c++ 11开始,有一种新的构造函数/赋值操作符。三原则现在变成了五原则,但是当不处理资源处理类时,最好不要编写复制或赋值构造函数。只有这些类需要实现操作,其他类可以直接使用它。这是零原则,也是我建议大家坚持的原则。同样,std::unique_pointer是一个很好的例子。而不是编写移动/复制构造函数,您的类可以只使用unique_ptrshared_ptr,并且内存管理被照顾。