在C ++中复制构造函数
这个问题在这里已经有了答案:
(1)成员变量的类型并不重要,它们的语义是。 规则很简单:
如果你没有提供拷贝构造函数,编译器会尝试为你生成一个拷贝构造函数。 这个默认生成的将对所有成员变量执行默认的复制操作。 对于类类型,这意味着调用复制构造函数。 对于原始类型,这意味着按位复制。
如果默认生成的构造函数执行你所需要的,不要声明你自己的。 如果它不能满足你的需求,请自己申报。 可以使用非原始成员变量和完全确定的默认复制语义创建一个类:
struct PersonId
{
std::string surname;
std::vector<std::string> givenNames;
};
同样,可以创建一个具有原始类型成员变量的类,其中默认的复制语义不会正常:
class UniqueNamed
{
int id;
UniqueNamed() : id(0) {}
public:
UniqueNamed(const UniqueNamed &src) : id(src.id + 1) {}
int getId() const { return id; }
static UniqueNamed initial;
};
所以它取决于类的语义,而不取决于其数据成员的类型。
这涉及C ++中复制,移动和授权语义以及它们的实现的一般概念。 你可能想读一些关于零,三,五规则的东西。
(1)当然,如果任何成员变量是不可复制的类型,并且你希望你的类是可复制的,你必须自己提供拷贝构造函数,因为缺省声明的类将被定义为删除。
如果需要通过复制每个数据成员的值来复制对象,则不需要编写一个; 隐式生成的将完全做到这一点。
如果在复制对象时需要发生其他情况,或者如果某些内容阻止了隐式对象的生成(例如, const
数据成员),并且您仍然希望能够复制该对象,则需要编写一。
如果你没有编写一个拷贝构造函数,就会创建一个缺省的拷贝构造函数,它会逐个拷贝你的类的每个字段,并调用它们的拷贝构造函数(如果有的话)。
例如 :
class Test {
public:
int toto;
char titi;
};
int main() {
Test a;
a.toto = 42;
a.titi = 'a';
Test b(a); // b will be initialized with same fields than a.
return (0);
}
注意这个方法:只用于简单的类,正如你所说的那样,只使用标准的C ++数据类型的字段。
这里最常见的错误是当你的类有一个指针字段时:指针被复制,但不被重新分配,所以你将有两个类的实例,指针指向同一个事物,如果其中一个修改或删除它,另一个人会感受到后果。
class Test {
public:
std::string* field;
Test() {
field = new std::string("toto");
}
~Test() {
delete (field);
}
};
int main () {
Test a; // a.field is allocated.
Test b(a); // b have the same pointer than a, as if you did b.field = a.field.
// Here a and b destructors are called. They will delete the same pointers twice.
// It will result as a segmentation fault.
return (0);
}
注意 :对于=
运算符也是如此,如果不超载的话。