c ++拷贝构造函数签名:重要吗?

时间:2012-10-02 10:52:59

标签: c++ copy const copy-constructor

我当前的实现使用了大量具有此语法的复制构造函数

MyClass::Myclass(Myclass* my_class)

它真的(functionnaly)与

不同吗?

MyClass::MyClass(const MyClass& my_class)

为什么?

我被告知第一个解决方案不是真正的复制构造函数。但是,进行更改意味着进行了大量的重构。

感谢!!!

5 个答案:

答案 0 :(得分:17)

在第一个不是复制构造函数而是转换构造函数的意义上它是不同的。它会从MyClass*转换为MyClass

根据定义,复制构造函数具有以下签名之一:

MyClass(MyClass& my_class)
MyClass(const MyClass& my_class)
//....
//combination of cv-qualifiers and other arguments that have default values

12.8。复制类对象

  

2)类X的非模板构造函数是一个复制构造函数(如果是)   第一个参数是X&类型,const X&,volatile X&或const volatile   X&,并且没有其他参数或其他所有参数   参数有默认参数(8.3.6).113)[例如:X :: X(const   X&)和X :: X(X&,int = 1)是复制构造函数。

编辑:你似乎让两者感到困惑。

说你有:

struct A
{
   A();
   A(A* other);
   A(const A& other);
};

A a;     //uses default constructor
A b(a);  //uses copy constructor
A c(&a); //uses conversion constructor

它们完全用于不同的目的。

答案 1 :(得分:7)

第一个版本是不是复制构造函数。就那么简单。它只是另一个构造函数。

X副本构造函数必须包含签名(X &, ...)(X const &, ...)(X volatile &, ...)(X const volatile &, ...),其中所有参数,但第一个具有默认值(如果它们存在)(并且它不能是模板)。


那就是说,你应该仔细考虑你违反零规则的原因:大多数精心设计的类不应该有任何用户定义的拷贝构造函数,拷贝赋值运算符或者根本就是析构函数,而是依靠精心设计的成员。你当前的构造函数使用指针这一事实让我想知道你的代码是否能像MyClass x = y;那样正确运行 - 值得检查。

答案 2 :(得分:5)

某些语言结构需要复制构造函数:

  • 传递值
  • 按值返回
  • 复制样式初始化(​​虽然在这种情况下通常会省略副本)

如果语言要求复制,并且您提供了复制构造函数,则可以使用它(假设cv资格是正常的)。

由于您尚未提供复制构造函数,因此您将获得编译器生成的复制构造函数。这通过复制每个数据成员来工作,即使这对您的班级来说不是正确的事情。例如,如果not-a-copy-constructor显式执行任何深层复制或分配资源,则需要禁止编译器生成的副本。

如果编译器生成的副本适用于您的类,那么您的非副本构造函数几乎是无害的。不过,我认为这不是一个特别好的主意:

void some_function(const MyClass &foo);

MyClass *ptr = new MyClass();
const MyClass *ptr2 = ptr;
some_function(ptr); // compiles, but copies *ptr and uses the copy
MyClass bar(ptr2);  // doesn't compile -- requires pointer-to-non-const

即使假设编译器生成的副本对您的类没有好处,进行必要的更改也不需要进行大量的重构。假设您的非构造函数实际上并未修改其参数指向的对象,因此在修复签名后,您有:

MyClass::MyClass(const MyClass* my_class) {
    // maybe treat null pointer specially
    // do stuff here
}

你需要:

MyClass::MyClass(const MyClass& my_class) {
    do_stuff(my_class);
}

MyClass::MyClass(const MyClass* my_class) {
    // maybe treat null pointer specially
    do_stuff(*my_class);
}

MyClass::do_stuff(const MyClass& my_class) {
    // do stuff here
}

您还需要将旧构造函数中的任何初始值设定项列表复制到新构造函数列表中,并根据my_class不是新构造函数中的指针进行修改。

删除旧的构造函数可能需要大量重构,因为您必须编辑使用它的任何代码。但是,您不必删除旧的构造函数,以便修复默认复制构造函数的任何问题。

答案 3 :(得分:1)

第一个例子不是复制构造函数。这意味着当您提供它时,编译器仍然为您提供具有等同于

的签名的默认复制构造函数
MyClass(const MyClass& my_class);

如果您正在对构造函数执行一些特殊操作,并且编译器提供的复制构造函数不遵循该逻辑,则应该实现复制构造函数或找到禁用它的方法。

答案 4 :(得分:1)

  

为什么我要使用复制构造函数而不是转换构造函数?

如果您将MyClass个对象提供给期望复制构造函数有效的代码,则可能会出现问题。

STL容器就是这种情况。例如,如果使用std::vector<MyClass>,则必须注意允许向量移动元素以使用其复制构造函数进行重新分配。

编译器提供的默认构造函数将执行浅拷贝,调用每个属性的复制构造函数,为指针等基类创建简单副本。如果您需要某种形式的深层复制,则必须正确地重写MyClass

的复制构造函数