有人可以解释为什么复制构造函数在这里被调用两次吗?
class A
{
int i;
public:
A(){cout<<"IN constr"<<endl;};
A(int x):i(x) {};
A (A &a)
{
cout<<"in copy"<<endl;
i= a.i;
}
};
class MyClass {
A var;
public:
MyClass(A a):var(a) {
}
};
int main() {
A a1;
MyClass m(a1);
return 0;
}
当我运行代码时,put是:
IN constr
in copy
in copy
我可以理解有一次它将a
复制到变量var
中,但是当它第二次被调用时?
答案 0 :(得分:8)
您正在传递构造函数参数按值,这是您的第二个副本来自的位置。如果您将构造函数签名更改为更规范的C ++,您将只获得一个副本:
MyClass(const A& a)
: var(a)
{
}
这个被称为参数传递的是 const reference ,而前C ++ 11它基本上是将参数传递给函数的首选方式。
如果你知道你将处理作为函数参数传递的临时对象,那么C ++ 11及更高版本也有传递rvalue-reference - 参见例如Pass by value vs pass by rvalue reference了解更多信息。
答案 1 :(得分:1)
第一个副本是从a1
到MyClass构造函数的参数a
,第二个副本是从参数a
到成员var
。
如果您想减少副本数量,您至少有两个选项:
将Joris提到的const引用传递给构造函数:
MyClass(A const &a) : var(a) {
}
如果可以有效地移动A,请按值a
移动到成员:
MyClass(A a) : var(std::move(a)) {
}
这样,不再需要A
的用户可以将其移动到新的MyClass实例中,而仍然需要A的用户可以按值传递它。
void useA(A &a);
void doSomethingWithM(MyClass & m);
void functionThatNeedsAAgain() {
A myImportantA;
MyClass m {myImportantA}; // copy myImportantA once
useA(myImportantA);
doSomethingWithM(m);
}
void functionThatDoesNotNeedAAgain() {
A tempA;
// no copy needed, as tempA will never be used again
MyClass m {std::move(tempA);
doSomethingWithM(m);
}
第三个选项是提供const A&
和A&&
的构造函数,但我会权衡代码重复与利益。
如果您想知道如果A
恰好是std::string
并且您想要涵盖临时A
的构建,可以采取的措施,请注意excellent talk由Nicolai Josuttis撰写。