21

我对复制构造函数的机制有点困惑。如我错了请纠正我:

如果一个方法将一个对象的引用作为参数,并且该类定义了一个复制构造函数,那么该类使用构造函数创建自身的副本,并将其传递给函数而不是对原始对象的引用?

此外,可以调用

Object * obj = new Object(&anotherObject);

创建另一个对象的副本?

4

6 回答 6

30

不,如果函数引用:

void f1( Object & o );   // call by reference

然后不复制。如果一个函数接受一个值:

void f2( Object o );   // call by value

然后编译器使用复制构造函数创建一个副本。

是的,当你说:

Object * obj = new Object(anotherObject);   // not &anotherObject

复制构造函数被显式使用(假设 anotherObject 是 Object 类型。)然而,这里的使用并没有什么神奇之处new——在这种情况下:

Object obj2(anotherObject);

还使用了复制构造函数。

于 2010-02-06T17:13:04.067 回答
7

如果方法将对象的引用作为参数,则不会调用复制构造函数。如果是这种情况,那么对复制构造函数本身的调用将导致无限循环(因为它将引用作为参数)。

该行不是调用复制构造函数的有效方法。它期望引用作为参数,而不是指针。

于 2010-02-06T17:13:04.520 回答
3

您进行方法调用的事实在这里并不重要。函数调用期间的引用参数初始化与独立的引用初始化没有什么不同,并且受相同的规则约束。

引用初始化的规则有点复杂,但底线是如果初始化器是左值(在你的情况下方法调用中的参数)并且引用的类型与初始化器的类型相同(即参数类型与实参类型相同),则直接绑定引用。即不创建副本。

Object a; // class type
Object &r = a; // no copying
const Object &cr = a; // no copying

如果不满足这些要求(例如,如果初始化程序是右值),那么一切都取决于。在某些情况下,复制可能并且将会发生。例如

const Object &tr = Object();

可以被编译器解释为

const Object &tr = Object(Object(Object(Object())));

具有依赖于实现的有限数量的复制。当然,出于效率原因,编译器通常会尽量不创建不必要的副本,即使它们被允许复制也是如此。

一个经常引起关于编译器复制行为有效性争论的经典示例是如下表达式中的引用初始化

Object a;
const Object &r = <some condition> ? a : Object();

熟悉 C++ 引用语义的人会理解,上述表达式可能是在引用初始化期间执行多余复制的标准许可背后的基本原理。

于 2010-02-06T17:28:06.320 回答
1

在这两种情况下都没有。在第一种情况下,传递对该对象本身的引用并且不创建副本。在第二种情况下,您将指针传递给构造函数,object因此不会创建副本。所以对象应该有一个构造函数(不是复制构造函数),类似于object(anotherClass*)

于 2010-02-06T17:14:07.097 回答
1

复制构造函数仅在按值传递时调用,而不是按引用传递。通过引用不需要复制(这是引用的一部分!)所以没有调用复制构造函数。

于 2010-02-06T17:20:37.770 回答
1

是的,像这样使用placement new:

Object dstObject;
new(&dstObject) Object(&anotherObject);
于 2017-06-09T06:39:25.213 回答