【发布时间】:2012-01-25 09:52:06
【问题描述】:
struct myType {
vector<char*> ls;
};
这里ls 持有指向char 的指针。如果没有为myType 提供用户定义的复制构造函数,myType 的默认复制构造函数是否会对ls 进行深层复制?
【问题讨论】:
-
我的意思是说vector是否持有任何指向原始或用户定义数据类型的指针(指向类的指针)
struct myType {
vector<char*> ls;
};
这里ls 持有指向char 的指针。如果没有为myType 提供用户定义的复制构造函数,myType 的默认复制构造函数是否会对ls 进行深层复制?
【问题讨论】:
这里 ls 持有指向 char 的指针。如果没有提供拷贝构造函数,默认拷贝构造函数会做深拷贝吗?
默认的复制构造函数将复制所有成员——即调用它们各自的复制构造函数。1所以是的,std::vector(就 C++ 而言没什么特别的)将被适当地复制。
但是,向量内的char* 元素指向的内存当然不会,因为 C++ 不知道也不关心指针指向什么。
但这里的解决方案不是提供自定义复制构造函数。这是使用数据结构 而不是原始指针 (char*)。这恰好是std::string(或std::vector<char>,具体取决于意图)。
1 从而创建一个复制操作的传递闭包——这就是深度复制通常的实现方式,当然复制操作的实现者总是可以突破。
【讨论】:
vector 的元素视为某种形式的间接时,术语“深拷贝”和“浅拷贝”才有意义。如果有人这样做,那么这是一个“浅拷贝”,但正如你所说的 vector 不在乎它的元素是指针还是其他任何东西。
char*元素肯定是被复制的。没有复制的是他们指向的东西。 (我很确定这就是你的意思。)
char *a = 0; char *b = a; 是一个深层副本,并且“将其称为其他任何东西都没有意义”。特别是,将其称为“副本”是没有意义的,这就是标准所称的(在这种情况下是副本分配)。所以我不能接受康拉德的术语,我希望其他人也不接受。我喜欢“成员复制”这个术语——每个成员都被复制,我们都知道复制指针意味着什么。涉及指针的“深度复制”似乎是有争议的——我认为这意味着复制引用,康拉德认为它没有。
默认的拷贝构造函数会做深拷贝吗?
当然不是。编译器无法知道谁拥有指向的内存。
如果需要深拷贝,则必须实现复制构造函数,并手动将每个char* 复制到新内存中,用于复制到object 中的vector。
如果您将char* 用作以零结尾的字符串,那么您应该真正改用std::string。如果这样做,默认构造函数就足够了。
【讨论】:
不,不会。
C++ 会递归调用所有子对象的拷贝ctor。因此它将调用向量的复制 ctor,进而调用 char* 的复制 ctor,后者将按值复制 char*。 C++ 永远不会自动分配内存和复制数据。它甚至不可能这样做,因为它不知道您指向的数据是什么,以及它应该复制多少。
当您使用字符串时,您应该更喜欢使用std::string,因为它会为您完成所有的复制工作。如果它是一些需要特殊处理的二进制数据缓冲区,那么您需要自己在复制 ctor 中执行此操作(完成后,请考虑一下考虑要求 C++ 为您执行此操作是否真的明智) .
当您编写自己的复制 ctor 时,您应该始终注意 Rule of Three
【讨论】: