我有一个包含普通构造函数和复制构造函数的类的以下简单代码
class largeObj
{
public:
largeObj()
{
printf("\nNormal constructor\n");
}
largeObj(const largeObj& mv)
{
printf("\nCopy constructor\n");
}
~largeObj()
{
printf("\nDestroying..\n");
}
void tryme()
{
printf("\nHi :)\n");
}
};
largeObj iReturnLargeObjects()
{
largeObj md;
return md;
}
int main()
{
largeObj mdd = iReturnLargeObjects();
mdd.tryme();
return 0;
}
输出
普通构造函数
复制构造函数
销毁..
嗨:)
我明白了。
但是,如果我替换以下行
largeObj mdd = iReturnLargeObjects();
与
largeObj& mdd = iReturnLargeObjects();
输出是一样的,为什么呢?
我的意思是:第一种情况下不应该有另一个副本(没有&)?这两条线之间有什么区别,为什么它们表现相同?
答案 0 :(得分:4)
largeObj& mdd = iReturnLargeObjects();
您不能将可变左值引用绑定到右值。这是非法的C ++,只允许某些特定的编译器扩展。但是,问题的语义没有改变,即使这个引用是const
因此赋值是合法的。
您的输出没有区别的原因是因为编译器优化称为RVO。这种优化(在C ++标准中明确允许)允许编译器在某些限制内跳过构造它确定不必要的对象 - 即使这样做会改变程序的语义,这使得它成为一种非常不寻常的优化。 p>
底线是:不要在副本/移动构造函数和析构函数中放置副作用,因为编译器可以消除它们,即使程序的正确性取决于它们被调用。
答案 1 :(得分:0)
你使用了什么编译器,我愿意打赌这是有效的,因为你使用的任何编译器都没有在返回后将未使用的堆栈变量归零,你没有得到seg错误,因为它仍然是你的堆栈。基本上md留在堆栈上,你在技术上仍然可以解决。两者之间的区别是
largeObj md;
是一个完整接收变量的变量。
largeObj&安培; mdd = iReturnLargeObjects();
是对由于惰性编译器仍然存在而导致的变量的引用。