gpt4 book ai didi

C++ 析构函数运行两次

转载 作者:行者123 更新时间:2023-12-05 04:23:15 25 4
gpt4 key购买 nike

请参阅下面的程序。该程序应该打印 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;
}

最佳答案

在 C++ 中,从函数返回对象会在调用者的上下文中复制构造对象,然后在返回的函数中销毁复制自对象。在某些情况下,可以省略此拷贝。

       Counter c;
return c;

这称为返回值优化,在这种情况下不是强制性的。此处的复制省略是允许的,但它是可选的。您使用的其中一个编译器省略了此拷贝,另一个则没有。

如果没有复制省略,编译器会在调用者的上下文中复制构造返回的对象。

Counter 缺少复制构造函数,因此显示的代码无法记录复制构造对象的实例。

只需添加一个复制构造函数:

class Counter {
public:
Counter() {
counter++;
}
Counter(const Counter &) {
counter++;
}
~Counter() {
counter--;
}
};

现在,无论是否使用复制省略,您都会得到预期的结果。

如果您在复制构造函数中设置断点,您会在从函数返回时看到断点命中(当使用不省略拷贝的编译器时)。

关于C++ 析构函数运行两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73759237/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com