class A
{
public:
A(const int n_);
A(const A& that_);
A& operator=(const A& that_);
};
A::A(const int n_)
{ cout << "A::A(int), n_=" << n_ << endl; }
A::A(const A& that_) // This is line 21
{ cout << "A::A(const A&)" << endl; }
A& A::operator=(const A& that_)
{ cout << "A::operator=(const A&)" << endl; }
int foo(const A& a_)
{ return 20; }
int main()
{
A a(foo(A(10))); // This is line 38
return 0;
}
执行此代码会给出o / p:
A :: A(int),n_ = 10
A :: A(int),n_ = 20
显然从不调用复制构造函数。
class A
{
public:
A(const int n_);
A& operator=(const A& that_);
private:
A(const A& that_);
};
但是,如果我们将其设为私有,则会发生此编译错误:
Test.cpp:在函数'int main()'中:
Test.cpp:21:错误:'A :: A(const A&amp;)'是私人的 Test.cpp:38:错误:在此上下文中
为什么编译器在实际上没有使用复制构造函数时会抱怨? 我正在使用gcc版本4.1.2 20070925(Red Hat 4.1.2-33)
答案 0 :(得分:12)
Core defect 391解释了这个问题。
基本上,当前的C ++标准要求在将类临时类型传递给const引用时可以使用复制构造函数。
此要求将在C ++ 0x中删除。
需要复制构造函数的逻辑来自于这种情况:
C f();
const C& r = f(); // a copy is generated for r to refer to
答案 1 :(得分:5)
2003年标准,§12.2/ 1,声明:
即使创作了 避免使用临时对象(12.8), 所有的语义限制必须是 尊重好像是临时对象 创建了。 [例子:即使 所有都没有调用复制构造函数 语义限制,如 无障碍(第11条),应为 满意。 ]
周围有类似的例子。从我收集的内容来看,编译器可以自由地生成临时值或优化它们。
答案 2 :(得分:3)
到目前为止,我看到你没有在任何地方使用复制构造函数。在语句foo(A(10))
中,您正在创建A类的临时对象,并将其作为const引用传递给foo。 foo返回一个整数,用于构造对象a
。因此,我没有看到复制构造函数涉及到何处以及NRVO如何进入图片。此外,我通过使复制构造函数私有编译以下代码,并在VS2008中编译良好。
using namespace std;
class A
{
public:
A(const int n_);
private:
A(const A& that_);
A& operator=(const A& that_);
};
A::A(const int n_)
{ cout << "A::A(int), n_=" << n_ << endl; }
A::A(const A& that_) // This is line 21
{ cout << "A::A(const A&)" << endl; }
A& A::operator=(const A& that_)
{
cout << "A::operator=(const A&)" << endl;
return *this;
}
int foo(const A& a_)
{ return 20; }
int main(int argc,char *argv[])
{
A a(foo(A(10))); // This is line 38
return 0;
}
答案 3 :(得分:2)
另一个评论:编译器在处理临时工时做了不同的事情。所以它不是关于复制构造函数,而是关于中间临时的。
A original(10);
foo( original ); // does compile
foo( A(10) ); // doesn't compile - needs a copy constructor
答案 4 :(得分:1)
不使用复制构造函数,但为了编译复制构造函数的代码需要可访问。
编辑:Comeau C ++编译器报告以下内容:
Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ noC++0x_extensions
"ComeauTest.c", line 38: error: "A::A(const A &)" (declared at line 17), required
for copy that was eliminated, is inaccessible
A a(foo(A(10))); // This is line 38
^
1 error detected in the compilation of "ComeauTest.c".
请注意,如果启用了C ++ 0x扩展,则可以在Comeau C ++编译器中进行编译。
答案 5 :(得分:1)
在表达式中:
A a(foo(A(10)));
子表达式A(10)
的结果是A
类型的 rvalue 。 (5.2.3 [expr.type.conv])
从 rvalue 初始化const引用时,编译器可以从 rvalue 创建一个临时值并将其绑定到引用。即使它选择不这样做,复制构造函数也必须是可访问的。 (8.5.3 [decl.init.ref])如果从引用兼容的 左值初始化引用,则不会出现这种情况,其中强制要求直接绑定。
由于foo
通过引用获取其参数而不是值,因此没有强制参数初始化本身的副本。
foo
返回一个int,因此此处没有A
的副本。
a
是从foo返回的int直接初始化的,所以这里没有A
的副本。
答案 6 :(得分:0)
通常,您不应该担心是否以及何时调用复制构造函数。关于何时删除对复制构造函数的调用或添加的内容,C ++标准非常宽松。如果你的类在逻辑上需要它,那么提供它(并且不要忘记析构函数和赋值运算符)是合理的规则。
答案 7 :(得分:0)
致电:
foo( A(10) );
在呼叫的生命周期内正在创建临时对象。正在使用复制构造函数来填充数据。执行调用后将删除临时对象。
致电:
{
A original(10);
foo( original );
}
退出该区块后原始文件被丢弃。它可以安全地用作参数。
为获得最佳速度,请使用临时变量按引用传递对象,编译器在优化过程中将丢弃该临时变量。