问题描述
假设我有以下代码
#pragma once
class Something {
public:
static Something& get();
private:
Something();
};
Something.cpp
#include "Something.hpp"
#include <iostream>
using namespace std;
Something& Something::get() {
static Something something;
return something;
}
Something::Something() {
cout << "Something()" << endl;
}
main.cpp
#include <iostream>
using namespace std;
struct SomethingElse {
~SomethingElse() {
Something::get();
cout << "~SomethingElse" << endl;
}
};
void func() {
static SomethingElse something_else;
// do something with something_else
}
int main() {
func();
return 0;
}
是否可以创建 Something
对象的多个实例?该标准对串行化销毁静态对象有何规定?
Can more than one instance of the Something
object ever be created? Does the standard say anything about serializing the destruction of static objects?
注意,我知道在不同的翻译单元中,文件级静态变量的破坏是不确定的,我想知道在函数范围内的静态变量(在C ++运行时中内置了经过双重检查的锁定模式)具有文件级静态变量的转换单元大小写,便于编译器根据变量在代码中的布局方式(静态)确保结构化和销毁的序列化,但是当函数被动态延迟创建变量时会发生什么情况叫吗?
Note I am aware the the destruction of file level static variables is undefined when across different translation units, I wanted to know what happens in the case of function scoped static variables (which have the double-checked locking pattern built into the C++ runtime) For the same translation unit case with file level static variables, its easy for the compiler to ensure serialization with construction and destruction based on how the variables are laid out in the code (static), but what happens when the variables are dynamically lazily created when the functions are called?
注意:原始变量呢?我们可以期望它们在程序结束之前包含它们的值吗?因为它们不需要被销毁.
Note What about for primitive variables? Can we expect them to contain their values till program end? Since they don't need to be destroyed.
在cppreference.com上找到了此内容( http://en.cppreference.com/w/cpp/utility/program/exit )
Found this on cppreference.com (http://en.cppreference.com/w/cpp/utility/program/exit)
如果这是真的,那么每个静态对象的销毁序列化吗?但我也发现了
If this is true then destruction for every static object is serialized? But I also found this
https://isocpp.org/wiki/faq/ctors#construct-on-first-use-v2 与标准相抵触
推荐答案
第一次在控件通过其声明时执行具有静态存储持续时间或线程存储持续时间的块范围变量的动态初始化.
Dynamic initialization of a block-scope variable with static storage duration or thread storage duration is performed the first time control passes through its declaration.
[basic.start.term]¶1
如果对具有静态存储持续时间的对象的构造函数的完成或动态初始化的排序要先于另一个对象的顺序进行,则在第二个对象的析构函数的初始化之前对第二个对象的析构函数的完成进行排序.
If the completion of the constructor or dynamic initialization of an object with static storage duration is sequenced before that of another, the completion of the destructor of the second is sequenced before the initiation of the destructor of the first.
¶2
如果函数包含具有静态或线程存储持续时间的块范围对象,并且该对象在具有静态或线程存储持续时间的对象的销毁过程中被调用,则该程序具有未定义的行为如果控制流通过了先前破坏的块范围对象的定义.
If a function contains a block-scope object of static or thread storage duration that has been destroyed and the function is called during the destruction of an object with static or thread storage duration, the program has undefined behaviour if the flow of control passes through the definition of the previously destroyed block-scope object.
正是在 SomethingElse
的析构函数中,我们冒着调用这种未定义行为的风险:
It is in the destructor of SomethingElse
that we risk invoking this undefined behaviour:
SomethingElse::~SomethingElse() {
Something::get();
}
如果存在具有静态存储持续时间的 SomethingElse
实例,则有四种可能性:
If there is an instance of SomethingElse
with static storage duration, then there are four possibilities:
-
Something
的单个实例是在SomethingElse
之前构造的.它的破坏将在SomethingElse
之后发生,因此行为已得到明确定义.
The single instance of
Something
was constructed before theSomethingElse
. Its destruction will happen after theSomethingElse
, so the behaviour is well defined.
Something
的单个实例是在 SomethingElse
之后构造的.它的破坏将发生在 SomethingElse
之前,因此行为如上所述是不确定的.
The single instance of Something
was constructed after the SomethingElse
. Its destruction will have happened before the SomethingElse
, so the behaviour is undefined as described above.
Something
的单个实例是在不同的线程中构造的,而与 SomethingElse
的构造没有同步.破坏可能同时发生,因此行为是不确定的.
The single instance of Something
was constructed in a different thread without being synchronized with respect to the construction of the SomethingElse
. The destructions may happen concurrently, so the behaviour is undefined.
尚未构建 Something
的实例(即,这是对 Something :: get
的首次调用).在这种情况下,程序要求在 SomethingElse
之后构造 Something
,这意味着 Something
的销毁必须在 SomethingElse
,但是由于已经开始销毁 SomethingElse
,因此这是一个矛盾,其行为是不确定的.(从技术上讲,先后顺序"关系中存在一个循环.)
No instance of Something
was yet constructed (i.e. this is the first call to Something::get
). In this case, the program calls for the construction of a Something
after the SomethingElse
, which means the destruction of the Something
must happen before the SomethingElse
, but since the destruction of the SomethingElse
has already commenced, this is a contradiction, and the behaviour is undefined. (Technically, there is a cycle in the "sequenced before" relation.)
这篇关于引用可能损坏的静态对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!