什么时候初始化静态 C++ 类成员?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1421671/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When are static C++ class members initialized?
提问by Tony the Pony
There appears to be no easy answer to this, but are there any assumptions that can be safely made about when a static class field can be accessed?
对此似乎没有简单的答案,但是是否可以安全地做出任何关于何时可以访问静态类字段的假设?
EDIT: The only safe assumption seems to be that all statics are initialized before the program commences (call to main
). So, as long as I don't reference statics from other static initialization code, I should have nothing to worry about?
编辑:唯一安全的假设似乎是所有静态都在程序开始之前初始化(调用main
)。那么,只要我不从其他静态初始化代码中引用静态,我就没有什么可担心的吗?
采纳答案by Tadeusz Kopec
The standard guarantees two things - that objects defined in the same translation unit (usually it means .cpp file) are initialized in order of their definitions (not declarations):
该标准保证两件事 - 在同一翻译单元中定义的对象(通常意味着 .cpp 文件)按照它们的定义(而不是声明)的顺序进行初始化:
3.6.2
3.6.2
The storage for objects with static storage duration (basic.stc.static) shall be zero-initialized (dcl.init) before any other initialization takes place. Zero-initialization and initialization with a constant expression are collectively called static initialization; all other initialization is dynamic initialization. Objects of POD types (basic.types) with static storage duration initialized with constant expressions (expr.const) shall be initialized before any dynamic initialization takes place. Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit.
具有静态存储持续时间 (basic.stc.static) 的对象的存储应在任何其他初始化发生之前进行零初始化 (dcl.init)。零初始化和用常量表达式初始化统称为静态初始化;所有其他初始化都是动态初始化。使用常量表达式 (expr.const) 初始化静态存储持续时间的 POD 类型 (basic.types) 对象应在任何动态初始化发生之前进行初始化。在同一个翻译单元的命名空间范围内定义并动态初始化的静态存储持续时间的对象应按照其定义在翻译单元中出现的顺序进行初始化。
The other guaranteed thing is that initialization of static objects from a translation unit will be done before use of any object or function from this translation unit:
另一个有保证的事情是,在使用来自该翻译单元的任何对象或函数之前,将完成来自翻译单元的静态对象的初始化:
It is implementation-defined whether or not the dynamic initialization (dcl.init, class.static, class.ctor, class.expl.init) of an object of namespace scope is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first use of any function or object defined in the same translation unit as the object to be initialized.
命名空间范围的对象的动态初始化(dcl.init、class.static、class.ctor、class.expl.init)是否在main的第一条语句之前完成是实现定义的。如果初始化推迟到 main 的第一条语句之后的某个时间点,则它应在第一次使用与要初始化的对象在同一翻译单元中定义的任何函数或对象之前发生。
Nothing else i guaranteed (especially order of initialization of objects defined in different translation units is implementation defined).
我没有其他保证(尤其是在不同翻译单元中定义的对象的初始化顺序是实现定义的)。
EDIT
As pointed in Suma's comment, it is also guaranteed that they are initialized before main
is entered.
编辑正如苏马的评论中所指出的,还保证它们在main
输入之前已初始化。
回答by ChrisW
They're initialized before the program starts (i.e. before main
is entered).
它们在程序启动之前(即在main
输入之前)被初始化。
When there are two or more definitions (of static data) in a single CPP file, then they're initialized in the sequence in which they're defined in the file (the one defined earlier/higher in the file is initialized before the next one is).
当单个 CPP 文件中有两个或多个(静态数据的)定义时,它们将按照在文件中定义的顺序进行初始化(文件中较早/较高定义的在下一个之前进行初始化)一个是)。
When there are two or more definitions (of static data) in more than one CPP file, the sequence in which the CPP files are processed is undefined/implementation-specific. This is a problem if the constructor of a global variable (called before the program is started) references another global variable defined in a different CPP file, which might not have been constructed yet. However, item 47 of Meyers' Effective C++(which is titled Ensure that global objects are initialized before they're used) does describes a work-around ...
当在一个以上的 CPP 文件中有两个或多个(静态数据的)定义时,处理 CPP 文件的顺序是未定义的/特定于实现的。如果全局变量的构造函数(在程序启动之前调用)引用了另一个在不同 CPP 文件中定义的全局变量,而该变量可能尚未构造,则会出现问题。但是,Meyers 的Effective C++的第47 项(标题为确保全局对象在使用前被初始化)确实描述了一种解决方法......
Define a static variable in a header file (it's static so you can have multiple instances of it without the linker complaining)
Have the constructor of that variable invoke whatever you need it to (in particular, construct the global singletons declared in the headers)
在头文件中定义一个静态变量(它是静态的,因此您可以拥有它的多个实例,而链接器不会抱怨)
让该变量的构造函数调用您需要的任何内容(特别是构造在头文件中声明的全局单例)
... which it says is a technique which may be used in some system header files e.g. to ensure that the cin
global variable is initialized before even your static variables' constructors use it.
...它说的是一种可以在某些系统头文件中使用的技术,例如确保cin
全局变量在您的静态变量的构造函数使用它之前被初始化。
回答by Paani
Your final conclusion in the Edit is correct. But the problem is the class static themselves. It's easier to say that my code will have class static members that don't refer to other global data/ class static members but once you take this route, things will go wrong soon. One approach that I have found useful in practice to not have class static data members but class static wrapper methods. These methods can then hold the static object within itself. For e.g.
您在编辑中的最终结论是正确的。但问题是类本身是静态的。可以更容易地说,我的代码将具有不引用其他全局数据/类静态成员的类静态成员,但是一旦你采取了这条路线,事情很快就会出错。我发现在实践中有用的一种方法是没有类静态数据成员,而是类静态包装器方法。然后这些方法可以在其自身中保存静态对象。例如
TypeX* Class2::getClass1Instance()
{
static TypeX obj1;
return &obj1;
}
TypeX* Class2::getClass1Instance()
{
static TypeX obj1;
return &obj1;
}
Note: An earlier answer says:
注意:较早的答案说:
The other guaranteed thing is that initialization of static objects from a translation unit will be done before use of any object or function from this translation unit
另一个有保证的事情是,在使用来自该翻译单元的任何对象或函数之前,将完成来自翻译单元的静态对象的初始化
This is not completely correct and the standard is incorrectly inferred here. This may not hold true if the function from a translation unit is called before main is entered.
这并不完全正确,此处错误地推断了标准。如果在输入 main 之前调用来自翻译单元的函数,则这可能不成立。
回答by vehomzzz
They can be initialized in an implementation file (.c/cpp/cc) files. Dont initialize them in .h as compiler will complain about multiple definitions.
它们可以在实现文件 (.c/cpp/cc) 文件中初始化。不要在 .h 中初始化它们,因为编译器会抱怨多个定义。
They are typically initialized before main, however order is uknown, hence avoid dependencies. They can certainly be accessed within member function. Keep in mind, order of initialization is unknown for static members. I would suggest to encapsulate a static member into the static function that will check if the member has been initialized.
它们通常在 main 之前初始化,但是顺序是未知的,因此避免依赖。它们当然可以在成员函数中访问。请记住,静态成员的初始化顺序是未知的。我建议将一个静态成员封装到静态函数中,该函数将检查该成员是否已被初始化。
回答by erelender
I believe it can be accessed anytime during the execution. What remains undefined is the initialization order of the static variables.
我相信它可以在执行过程中随时访问。未定义的是静态变量的初始化顺序。
回答by Dentoid
There isn't a totally trivial answer to this question, but basically they're initialized just before control is passed to the entry point (main) of your program. The order in which they are initialized is (to my knowledge) undefined and may be compiler specific.
这个问题没有一个完全微不足道的答案,但基本上它们是在控制传递到程序的入口点(主)之前初始化的。它们的初始化顺序(据我所知)是未定义的,并且可能是特定于编译器的。
EDIT: To clarify, your added assumption is correct. As long as you're only accessing it post main-entry, you don't really have to worry about when/how it's initialized. It will be initialized by that time.
编辑:澄清一下,您添加的假设是正确的。只要您仅在主条目后访问它,您就不必担心它何时/如何初始化。届时它将被初始化。
回答by Dentoid
i think the main thread of a proccess will execute the following five steps in order
我认为一个进程的主线程会依次执行以下五个步骤
initialization of CRT library
static initialization
execution of main() function
static unitialization
unitialization of CRT library
CRT库的初始化
静态初始化
main() 函数的执行
静态单元化
CRT库的统一化
you want reference statics from other static initialization code? maybe the following codes work:
你想从其他静态初始化代码中引用静态吗?也许以下代码有效:
class A;
static auto_ptr<A> a(auto_ptr<A>(&GetStaticA()));
A &GetStaticA(void)
{
static A *a = NULL; //the static basic type variables initialized with constant experession will be initialized earlier than the other static ones
if (a == NULL)
{
a = new A();
return *a;
}
}