【发布时间】:2020-10-27 01:25:59
【问题描述】:
考虑这样的情况:
#include <iostream>
int foo() {
static struct S {
int value;
S(int a): value(a) {}~S() {
std::cout << "End is nigh";
}
}
s(42);
return s.value;
}
int main() {
return foo();
}
在编译器的实现中,我在代码中研究了这些结果,该代码通过调用_atexit 设置S::~S(),即在main() 退出后的某个时刻本地静态对象将不复存在。
如果全局静态/外部作用域中对象的析构函数调用具有函数局部静态作用域的函数,根据定义,该函数在第一次执行进入此作用域时被构造,并且来自析构函数的调用是第一次?这也可能是对象函数局部静态作用域的析构函数在函数局部静态作用域中构造另一个对象的情况。
这可能是代码库依赖于 Scott Meyers 的单例实现的多个实例的情况,其中对象实例是函数局部静态变量。我不确定如果这样的单例必须在这个执行阶段访问标准流会发生什么,是否确定它们在atexit 处理程序之后何时停止运行。
【问题讨论】:
-
我认为你应该改写你的问题更准确。我想你是在问,如果全局静态/外部范围内的对象的析构函数调用具有函数局部静态范围的函数,根据定义,该函数在第一次执行进入此范围并从析构函数是第一次。无论这是未定义的行为,还是存在可以采用任何一种方式的声明顺序依赖项。这实际上是一个非常有趣的语言律师问题。
-
@SamVarshavchik 我可以复制你的措辞吗?嘿,英语不是我的母语,现在是凌晨 4 点
-
做我的客人,不客气。
-
在什么情况下您希望对象生命周期在
main()返回之后开始?在这些情况中,有多少会存在替代实现或设计选择,其中该对象的至少部分生命周期(例如其构造)发生在main()返回之前?在任何情况下,标准 I/O 流(cout等)都由标准保证可在静态对象的构造函数和析构函数中访问。 -
我在标准中没有看到任何直接解决此问题的内容。使用已销毁的静态对象调用函数是未定义的行为。我怀疑第一次调用带有静态变量的函数要么是好的一次(由于静态对象销毁规则,它会在完成当前对象析构函数后立即被销毁)然后是 UB,或者可能总是只是 UB。跨度>