一般说明(在您编辑问题之前):
仅仅在复制构造函数中调用复制赋值运算符并不是一个通用的解决方案。它们的意思不同(我的意思是,如果它们的意思相同,为什么要在那里)。
当(现有!)对象被分配一个新值时,将调用赋值运算符。如果该对象属于同一类型,我们也称其为复制分配,因为典型的实现只是简单地复制内容(但可能共享一些引用的东西,例如共享指针或具有共享数据的 PIMPL 类)。除非您提供,否则编译器会自动实现复制赋值运算符。它使用其类型的赋值运算符复制每个成员(原始成员也被复制)。
当一个(还不存在的!)对象被分配一个相同类型的初始值时,复制构造函数被调用,即它应该用一个现有对象的副本进行初始化。同样,如果您不提供复制构造函数,编译器会为您生成一个,再次使用复制构造函数复制成员。
如果您从复制构造函数中调用赋值运算符,这意味着生成的程序在复制初始化新对象时执行以下步骤:
- (除非您使用成员初始化器列表:)它使用默认构造函数初始化非原始类成员。原始类型未初始化。
- 然后,调用赋值运算符。如果您没有定义一个,它会复制所有成员。
所以在大多数情况下应该没问题,但是在某些情况下这不起作用,特别是如果您的班级有无法默认构造或无法分配的成员。如果是这种情况,并且它们仍然可以复制构造(与复制分配相反),则必须手动初始化复制构造函数的成员初始化列表中的成员。
编辑(因为问题得到了编辑):在你的情况下,data
是一个原始类型(所有指针都被认为是原始的),所以你必须在调用赋值运算符之前在复制构造函数中正确初始化它。如果你不这样做,赋值将删除一个未初始化的指针。所以你应该做的最好的(以避免代码重复;如果你这样做可能会更有效):
Array<T, ROW, COL>(const Array<T, ROW, COL> &array) :
data(0) // Now it is at least initialized, although inefficient
{
*this = array;
}
然后赋值运算符将尝试删除一个空指针,这没关系(它什么也不做),然后执行实际的复制。将data(0)
初始化视为“默认构造的 null Array<...>
”对象,只是暂时的。(也许您已经提供了一个不分配外部内存的空对象?)