如果类成员是向量,我们是不是应该显式编写复制构造函数?

Posted

技术标签:

【中文标题】如果类成员是向量,我们是不是应该显式编写复制构造函数?【英文标题】:Should we explicitly write a copy constructor if the class member is a vector?如果类成员是向量,我们是否应该显式编写复制构造函数? 【发布时间】:2012-01-25 09:52:06 【问题描述】:
struct myType 
    vector<char*> ls;
;

这里ls 持有指向char 的指针。如果没有为myType 提供用户定义的复制构造函数,myType 的默认复制构造函数是否会对ls 进行深层复制?

【问题讨论】:

我的意思是说vector是否持有任何指向原始或用户定义数据类型的指针(指向类的指针) 【参考方案1】:

这里 ls 持有指向 char 的指针。如果没有提供拷贝构造函数,默认拷贝构造函数会做深拷贝吗?

默认的复制构造函数将复制所有成员——即调用它们各自的复制构造函数。1所以是的,std::vector(就 C++ 而言没什么特别的)将被适当地复制。

但是,向量内的char* 元素指向的内存当然不会,因为 C++ 不知道也不关心指针指向什么。

但这里的解决方案不是提供自定义复制构造函数。这是使用数据结构 而不是原始指针 (char*)。这恰好是std::string(或std::vector&lt;char&gt;,具体取决于意图)。


1 从而创建一个复制操作的传递闭包——这就是深度复制通常的实现方式,当然复制操作的实现者总是可以突破。

【讨论】:

“这是对“深拷贝”的一个很好的定义”——如果这是对“深拷贝”的一个很好的定义,那么“浅拷贝”会是什么样子?我个人认为这是一个“副本”。当且仅当人们将vector 的元素视为某种形式的间接时,术语“深拷贝”和“浅拷贝”才有意义。如果有人这样做,那么这是一个“浅拷贝”,但正如你所说的 vector 不在乎它的元素是指针还是其他任何东西。 @Steve 根据复制构造的语言机制,恕我直言,区别仅对指针/引用分配有意义。但是由于 ctor 是 C++ 定义复制操作的方式,并且由于调用 one ctor 对其所有成员执行此复制操作的传递闭包,因此调用它没有任何意义,除非深度复制,恕我直言。如果你没有在闭包层次结构中提供复制语义(通过使用原始指针而不通过封装将其与复制语义相关联),那么你明确告诉 C++ 放弃它的复制机制。 只是关于措辞的一点点:向量内的char*元素肯定是被复制的。没有复制的是他们指向的东西。 (我很确定这就是你的意思。) 将其称为深拷贝是错误的。严格地说它是什么:成员复制。这是深拷贝还是浅拷贝在很大程度上取决于数据的结构。说这是一个深拷贝也意味着复制一个指针(而不是引用的对象)将是一个深拷贝。 @edA-qa mort-ora-y:同意,根据 Konrad 的定义,char *a = 0; char *b = a; 是一个深层副本,并且“将其称为其他任何东西都没有意义”。特别是,将其称为“副本”是没有意义的,这就是标准所称的(在这种情况下是副本分配)。所以我不能接受康拉德的术语,我希望其他人也不接受。我喜欢“成员复制”这个术语——每个成员都被复制,我们都知道复制指针意味着什么。涉及指针的“深度复制”似乎是有争议的——我认为这意味着复制引用,康拉德认为它没有。【参考方案2】:

默认的拷贝构造函数会做深拷贝吗?

当然不是。编译器无法知道谁拥有指向的内存。

如果需要深拷贝,则必须实现复制构造函数,并手动将每个char* 复制到新内存中,用于复制到object 中的vector

如果您将char* 用作以零结尾的字符串,那么您应该真正改用std::string。如果这样做,默认构造函数就足够了。

【讨论】:

【参考方案3】:

不,不会。

C++ 会递归调用所有子对象的拷贝ctor。因此它将调用向量的复制 ctor,进而调用 char* 的复制 ctor,后者将按值复制 char*。 C++ 永远不会自动分配内存和复制数据。它甚至不可能这样做,因为它不知道您指向的数据是什么,以及它应该复制多少。

当您使用字符串时,您应该更喜欢使用std::string,因为它会为您完成所有的复制工作。如果它是一些需要特殊处理的二进制数据缓冲区,那么您需要自己在复制 ctor 中执行此操作(完成后,请考虑一下考虑要求 C++ 为您执行此操作是否真的明智) .

当您编写自己的复制 ctor 时,您应该始终注意 Rule of Three

【讨论】:

以上是关于如果类成员是向量,我们是不是应该显式编写复制构造函数?的主要内容,如果未能解决你的问题,请参考以下文章

Problem E: 向量的运算

私有成员是不是应该在惯用的 C# 中显式声明为私有? [关闭]

C++中的派生类,可以不定义对象直接调用基类的成员和调用自己的成员函数嘛???

我定义了一个非拷贝构造函数;复制构造函数是不是仍会被隐式定义?

JAVA中构造方法和普通方法的区别

C++中派生类的构造函数怎么显式调用基类构造函数?