C++:何时(以及如何)调用 C++ 全局静态构造函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1271248/
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
C++: When (and how) are C++ Global Static Constructors Called?
提问by Matthew Iselin
I'm working on some C++ code and I've run into a question which has been nagging me for a while... Assuming I'm compiling with GCC on a Linux host for an ELF target, where are global static constructors and destructors called?
我正在处理一些 C++ 代码,我遇到了一个困扰我一段时间的问题......假设我正在 Linux 主机上为 ELF 目标使用 GCC 进行编译,全局静态构造函数和析构函数在哪里叫?
I've heard there's a function _init in crtbegin.o, and a function _fini in crtend.o. Are these called by crt0.o? Or does the dynamic linker actually detect their presence in the loaded binary and call them? If so, whendoes it actually call them?
我听说在 crtbegin.o 中有一个函数 _init,在 crtend.o 中有一个函数 _fini。这些是由 crt0.o 调用的吗?或者动态链接器是否真的检测到它们在加载的二进制文件中的存在并调用它们?如果是这样,它实际上什么时候调用它们?
I'm mainly interested to know so I can understand what's happening behind the scenes as my code is loaded, executed, and then unloaded at runtime.
我主要想知道这样我就可以了解在我的代码在运行时加载、执行和卸载时幕后发生的事情。
Thanks in advance!
提前致谢!
Update: I'm basically trying to figure out the general time at which the constructors are called. I don't want to make assumptions in my code based on this information, it's more or less to get a better understanding of what's happening at the lower levels when my program loads. I understand this is quite OS-specific, but I have tried to narrow it down a little in this question.
更新:我基本上是想弄清楚调用构造函数的一般时间。我不想根据这些信息在我的代码中做出假设,或多或少是为了更好地了解我的程序加载时在较低级别发生的事情。我知道这是特定于操作系统的,但我试图在这个问题中缩小范围。
采纳答案by Leandro T. C. Melo
When talking about non-local static objects there are not many guarantees. As you already know (and it's also been mentioned here), it should not write code that depends on that. The static initialization order fiasco...
在谈论非本地静态对象时,没有多少保证。正如您已经知道的(这里也提到过),它不应该编写依赖于此的代码。静态初始化命令失败...
Static objects goes through a two-phase initialization: static initialization and dynamic initialization. The former happens first and performs zero-initialization or initialization by constant expressions. The latter happens after all static initialization is done. This is when constructors are called, for example.
静态对象经过两个阶段的初始化:静态初始化和动态初始化。前者首先发生,并通过常量表达式执行零初始化或初始化。后者在所有静态初始化完成后发生。例如,这是调用构造函数的时候。
In general, this initialization happens at some time before main(). However, as opposed to what many people think even that is not guaranteed by the C++ standard. What is in fact guaranteed is that the initialization is done before the use of any function or object defined in the same translation unit as the object being initialized. Notice that this is not OS specific. This is C++ rules. Here's a quote from the Standard:
通常,此初始化发生在 main() 之前的某个时间。然而,与许多人认为的相反,C++ 标准并不能保证这一点。实际上可以保证的是,在使用与正在初始化的对象相同的翻译单元中定义的任何函数或对象之前,初始化已完成。请注意,这不是特定于操作系统的。这是 C++ 规则。这是标准中的引用:
It is implementation-defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) 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
命名空间范围的对象的动态初始化(8.5、9.4、12.1、12.6.1)是否在main的第一条语句之前完成是实现定义的。如果初始化推迟到 main 的第一条语句之后的某个时间点,则它应在第一次使用与要初始化的对象在同一翻译单元中定义的任何函数或对象之前发生
回答by ebo
This depends heavy on the compiler and runtime. It's not a good idea to make any assumptions on the time global objects are constructed.
这在很大程度上取决于编译器和运行时。对构建全局对象的时间做出任何假设并不是一个好主意。
This is especially a problem if you have a static object which depends on another one being already constructed.
如果您有一个静态对象依赖于已经构建的另一个对象,则这尤其成问题。
This is called "static initialization order fiasco". Even if thats not the case in your code, the C++Lite FAQ articles on that topic are worth a read.
这称为“静态初始化顺序失败”。即使您的代码并非如此,关于该主题的 C++Lite FAQ 文章也值得一读。
回答by Gunther Piez
This is not OS specific, rather its compiler specific.
这不是特定于操作系统的,而是特定于其编译器的。
You have given the answer, initialization is done in __init
.
你已经给出了答案,初始化是在__init
.
For the second part, in gcc you can guarantee the order of initialization with a ____attribute____((init_priority(PRIORITY)))
attached to a variable definition, where PRIORITY
is some relative value, with lower numbers initialized first.
对于第二部分,在 gcc 中,您可以通过____attribute____((init_priority(PRIORITY)))
附加到变量定义来保证初始化顺序,其中PRIORITY
是一些相对值,首先初始化较低的数字。
回答by Martin York
The grantees you have:
您拥有的受助人:
- All static non-local objects in the global namespace are constructed before main()
- All static non-local objects in another namespace are constructed before any functions/methods in that namespace are used (Thus allowing the compiler to potentially lazy evaluate them [but don't count on this behavior]).
- All static non-local objects in a translation unit are constructed in the order of declaration.
- Nothing is defined about the order between translation units.
- All static non-local objects are destroyed in the reverse order of creation. (This includes the static function variables (which are lazily created on first use).
- 全局命名空间中的所有静态非本地对象都是在 main() 之前构造的
- 另一个命名空间中的所有静态非本地对象都是在使用该命名空间中的任何函数/方法之前构造的(因此允许编译器潜在地对它们进行延迟评估 [但不要指望这种行为])。
- 翻译单元中的所有静态非本地对象都是按照声明的顺序构造的。
- 没有定义翻译单元之间的顺序。
- 所有静态非本地对象都以与创建相反的顺序销毁。(这包括静态函数变量(首次使用时延迟创建)。
If you have globals that have dependencies on each other you have two options:
如果您有相互依赖的全局变量,您有两个选择:
- Put them in the same translation unit.
- Transform them into static function variables retrieved and constructed on first use.
- 将它们放在同一个翻译单元中。
- 将它们转换为首次使用时检索和构造的静态函数变量。
Example 1: Global A's constructor uses Global log
示例 1:Global A 的构造函数使用 Global log
class AType
{ AType() { log.report("A Constructed");}};
LogType log;
AType A;
// Or
Class AType()
{ AType() { getLog().report("A Constructed");}};
LogType& getLog()
{
static LogType log;
return log;
}
// Define A anywhere;
Example Global B's destructor uses Global log
示例全局 B 的析构函数使用全局日志
Here you have to grantee that the object log is not destroyed before the object B. This means that log must be fully constructed before B (as the reverse order of destruction rule will then apply). Again the same techniques can be used. Either put them in the same translation unit or use a function to get log.
在这里,您必须授予对象日志不会在对象 B 之前销毁。这意味着日志必须在 B 之前完全构造(因为随后将应用销毁规则的相反顺序)。同样可以使用相同的技术。要么将它们放在同一个翻译单元中,要么使用函数来获取日志。
class BType
{ ~BType() { log.report("B Destroyed");}};
LogType log;
BType B; // B constructed after log (so B will be destroyed first)
// Or
Class BType()
{ BType() { getLog();}
/*
* If log is used in the destructor then it must not be destroyed before B
* This means it must be constructed before B
* (reverse order destruction guarantees that it will then be destroyed after B)
*
* To achieve this just call the getLog() function in the constructor.
* This means that 'log' will be fully constructed before this object.
* This means it will be destroyed after and thus safe to use in the destructor.
*/
~BType() { getLog().report("B Destroyed");}
};
LogType& getLog()
{
static LogType log;
return log;
}
// Define B anywhere;
回答by sbi
According to the C++ standard they are called before any function or object of their translation unit is used. Note that for objects in the global namespace this would mean they are initialized before main()
is called. (See ltcmelo'sand Martin'sanswers for mote details and a discussion of this.)
根据 C++ 标准,在使用其翻译单元的任何函数或对象之前调用它们。请注意,对于全局命名空间中的对象,这意味着它们在main()
调用之前已初始化。(有关详细信息和对此的讨论,请参阅ltcmelo和Martin 的回答。)