题
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的:在函数“诠释主()”:结果 TEST.CPP:21:错误:“A :: A(const的A&)”是私有的结果 TEST.CPP:38:错误:这个上下文中
为什么编译器抱怨时,它实际上并不使用拷贝构造函数?结果 我使用gcc版本4.1.2 20070925(红帽4.1.2-33)
解决方案
核心缺陷391 解释该问题。
基本上,当前的C ++标准要求一个拷贝构造使临时类型的一个const参考时是可用的。
这要求将C ++ 0x中被移除。
后面需要复制构造逻辑来源于此情况下:
C f();
const C& r = f(); // a copy is generated for r to refer to
其他提示
在2003标准,在§12.2/ 1,规定:
即使当创建的 临时对象被避免(12.8), 所有的语义限制必须是 推崇为如果临时对象 已创建。 [实施例:即使 拷贝构造函数不叫,一切 语义的限制,例如 可访问性(第11条),应 满意。 ]
有围绕类似的例子。从我所收集,编译器可以自由生成的临时或优化他们离开。
据我看你是不是使用拷贝构造函数的任何地方。在声明中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;
}
又一个备注:使用临时工作时,编译器做不同的事情。所以它不是关于拷贝构造函数,它是关于中间暂时的。
A original(10);
foo( original ); // does compile
foo( A(10) ); // doesn't compile - needs a copy constructor
在表达式:
A a(foo(A(10)));
子表达式A(10)
的结果是一个右值类型A
的。 (5.2.3 [expr.type.conv])
当初始化从右值编译器可以从右值创建临时和结合,为所述参考const引用。即使选择不,拷贝构造函数必须是可访问。 (8.5.3 [decl.init.ref])这将不会是这种情况,如果有基准正在从一个参考兼容 左值其中直接结合的任务初始化。
如foo
需要通过引用而不是值及其参数,也没有规定对自变量初始化本身。
foo
返回int,所以没有一个A
的副本在这里。
a
是直接从由富返回的INT初始化,所以没有A
这里的副本。
在拷贝构造没有被使用,但为了使代码编译拷贝构造需要是可访问的。
编辑:科莫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扩展被启用,它编译在科莫C ++编译器的罚款。
在一般情况下,你不应该对是否以及何时拷贝构造函数被调用去担心。 C ++标准是相当宽松的有关何时拷贝构造函数调用将被删除,或为此事增加。如果您的类逻辑需要它,它提供了(不要忘记析构函数和赋值运算符)是合理的规则。
致电时:
foo( A(10) );
时,该呼叫的生命周期中被创建的临时对象。复制构造被用来填充数据。临时对象被调用的执行之后被去除。
致电时:
{
A original(10);
foo( original );
}
在原始正在离开块后丢弃。它可以安全地被用作一个参数。
有关最佳速度,通过引用传递的对象,使用将被编译器在优化过程被丢弃临时变量。