c++ - 为什么析构函数被执行了两次?

标签 c++ inheritance visual-studio-2017 destructor pass-by-value

#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/

相关文章:

php - 如何访问特征中的类成员(或获得类似的行为)?

c# - 为 ASP.NET 自定义发布

docker - 从 Docker Windows 容器远程调试 .Net Core 控制台应用程序时,Visual Studio 2017 不加载调试符号

c++ - std::search 和 std::find_first_of 之间的区别

c++ - 将 SQLite 数据库中的数据保存到变量中

带有模板的 C++ Clang 优化错误

c++ - 使用保留标识符时,using 命令是否应该发出警告?

c++ - 继承实际上会导致类的成员为 'inherited' 吗?

.net - Entity Framework - 查询继承

c++ - 调试显示不正确值的 64 位 DLL 检查器