请看下面的程序。程序应该打印1,因为计数器对象1仍然存在,但是当用GCC编译时,它打印0。为什么会这样?这是编译器错误吗?这只发生在从不同的作用域返回时。删除if完全修复了所有编译器上的错误。
#include <iostream>
int counter = 0;
class Counter {
public:
Counter() {
counter++;
}
~Counter() {
counter--;
}
};
Counter test() {
if (true) { // REMOVING THIS FIXES IT
Counter c;
return c;
} else {
throw std::logic_error("Impossible!");
}
}
int main() {
Counter c = test();
std::cout << counter << std::endl; // 0 on GCC (incorrect), 1 on clang (correct)
return 0;
}
2条答案
按热度按时间wbgh16ku1#
在C++中,从一个函数返回一个对象时,在调用方的上下文中复制构造该对象,然后在返回的函数中销毁复制自的对象。在某些情况下,这种复制可以省略。
这被称为返回值优化,在这种情况下它不是强制的。这里的副本省略是允许的,但它是可选的。你使用的编译器之一省略了这个副本,另一个没有。
如果没有复制省略,编译器会在调用方的上下文中复制构造返回的对象。
这个
Counter
缺少复制构造函数,因此显示的代码无法记录复制构造对象的示例。只需添加一个复制构造函数:
现在,无论是否使用副本省略,您都将获得预期的结果。
如果你在复制构造函数中设置了断点,你会在从函数返回时看到断点命中(当使用的编译器不取消复制时)。
qqrboqgw2#
destructor
会在中有对象的范围结尾呼叫。1.当第一行--在
main
--被激励时,它将调用test()
。1.当您将条件设为true时,它会建立一个对象,这个对象会将
counter
加1。1.它将是
return c
,但另一方面,它是作用域的结尾,这意味着将调用destructor
,因此是counter--
。老实说,我对我的回答也没有把握,但我认为那是什么。