C++是否会调用全局和类静态变量的析构函数?

64

根据我的示例程序,看起来它确实在两种情况下都调用了析构函数。由于全局变量和类静态变量应该分配在程序堆栈的数据段中,那么在什么时候调用它们的析构函数呢?

2个回答

74

来自 C++03 标准的第 § 3.6.3 节:

具有静态存储期(在块作用域或命名空间作用域中声明)的已初始化对象的析构函数(§ 12.4)会在从 main 函数返回以及调用 exit 函数(§ 18.3)时被调用。这些对象的销毁顺序与它们构造完成的顺序相反,或者与它们动态初始化完成的顺序相反。如果一个对象是静态初始化的,则该对象的销毁顺序与它被动态初始化时的顺序相同。对于数组或类类型的对象,所有子对象都将在构造子对象期间初始化的任何具有静态存储期的局部对象被销毁之前销毁。

此外,§ 9.4.2 的第 7 条规定:

静态数据成员的初始化和销毁与非局部对象(§ 3.6.2、3.6.3)完全相同。

然而,如果一个析构函数没有可观察到的行为,它可能不会被调用。Terry Mahaffey 在他的回答中详细解释了这一点。


2
仅作观察:Visual C++ 2010似乎忽略了这个标准(以及其他一些标准)。我无法在测试析构函数中捕获断点。请参见:http://pastebin.com/sCMFYhzZ - progician
1
@progician:析构函数是否具有可观察的行为?VC++ '10 可能允许省略析构函数调用。尝试在析构函数中打印提示,然后读取输入,或者在其中打开文件并写入内容。 - outis
1
当然,如果VC++忽略了标准,我也不会太惊讶。 - outis
就我个人而言,我在使用VS2008SP1时也遇到了这个问题。添加了printf语句,但仍然无法正常工作。这是一个问题,因为我正试图按照curl的文档调用curl_global_cleanup()函数。 - Mark McKenna

6

在"main"函数之后的某个位置

(你不能确定或依赖于它们被调用的确切顺序)


9
它发生在 std::cout 被销毁之前。也就是说,你可以在那里打印东西。 - MSalters
1
@MSalters 我猜这只是你特定实现的细节和/或你声明对象的顺序相对于 cout 或第一个调用它的构造函数(例如 operator<<() )。我怀疑这并不是保证的,如果是这样,我会再次强调这个答案中的“不能依赖”。 - underscore_d
2
@underscore_d:不,这绝对是有保证的。这是因为标准库在实现中是特殊的/已知的。 - MSalters
1
@MSalters 谢谢,你的评论指引了我到这里:https://dev59.com/zmoy5IYBdhLWcg3wFqFT 顶部答案和Jerry Coffin在第二个答案上的评论似乎是最相关的部分。这是我今天学到的新东西! - underscore_d

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接