#include <iostream>
using namespace std;
class Car
{
public:
~Car() { cout << "Car is destructed." << endl; }
};
class Taxi :public Car
{
public:
~Taxi() {cout << "Taxi is destructed." << endl; }
};
void test(Car c) {}
int main()
{
Taxi taxi;
test(taxi);
return 0;
}
这是输出:
Car is destructed.
Car is destructed.
Taxi is destructed.
Car is destructed.
我使用MS Visual Studio Community 2017(抱歉,我不知道如何查看Visual C++的版本)。
当我使用 Debug模式时。我发现离开 void test(Car c){ }
时会执行一个析构函数。函数体如预期的那样。当 test(taxi);
时,会出现一个额外的析构函数。结束了。
test(Car c)
函数使用值作为形式参数。
前往该功能时会复制汽车。
所以我以为离开该功能时只会有一个“汽车被破坏”。
但实际上在离开该函数时有两个“Car is destructed”。(第一行和第二行如输出所示)
为什么有两个“汽车被毁”?谢谢。
==============
当我在 class Car
中添加虚拟函数时
例如:virtual void drive() {}
然后我得到预期的输出。
Car is destructed.
Taxi is destructed.
Car is destructed.
最佳答案
看起来 Visual Studio 编译器在为函数调用切片 taxi
时采取了一些捷径,具有讽刺意味的是,这导致它完成的工作比预期的要多。
首先,它会获取您的taxi
并从中复制构造Car
,以便参数匹配。
然后,它再次复制 Car
以进行值传递。
当您添加用户定义的复制构造函数时,这种行为就会消失,因此编译器似乎是出于自己的原因(也许在内部,这是一个更简单的代码路径)这样做,利用了“允许”的事实因为拷贝本身是微不足道的。事实上,您仍然可以使用非平凡的析构函数观察到这种行为,这有点反常。
我不知道这在多大程度上是合法的(特别是自 C++17 以来),或者为什么编译器会采用这种方法,但我同意这不是我的输出会直觉地预期。 GCC 和 Clang 都没有这样做,尽管它们可能以相同的方式做事,但更擅长省略拷贝。我已经注意到,即使是 VS 2019 在保证消除方面仍然不是很好。
关于c++ - 为什么析构函数被执行了两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58579523/