简体   繁体   English

是否保证静态对象被初始化

[英]Is static object guaranteed to be initialized

I am trying to learn about initialization of static objects. 我试图了解静态对象的初始化。 Static initialization seems pretty straight forward, assuming you understand constant expressions and constexpr . 假设你理解常量表达式和constexpr ,静态初始化似乎很简单。 Dynamic initialization seems quite a bit more tricky. 动态初始化似乎有点棘手。

[basic.start.init]/4 [basic.start.init / 4

It is implementation-defined whether the dynamic initialization of a non-local variable with static storage duration is done before the first statement of main. 实现定义是否在第一个main语句之前完成具有静态存储持续时间的非局部变量的动态初始化。 If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first odr-use (3.2) of any function or variable defined in the same translation unit as the variable to be initialized. 如果初始化延迟到第一个main语句之后的某个时间点,则应该在与要初始化的变量相同的转换单元中定义的任何函数或变量的第一个odr-use(3.2)之前发生。

footnote 34 脚注34

A non-local variable with static storage duration having initialization with side-effects must be initialized even if it is not odr-used (3.2, 3.7.1). 具有静态存储持续时间的非局部变量必须初始化,即使它没有使用odr-used(3.2,3.7.1)。

[basic.start.init]/5 [basic.start.init] / 5

It is implementation-defined whether the dynamic initialization of a non-local variable with static or thread storage duration is done before the first statement of the initial function of the thread. 实现 - 定义是否在线程的初始函数的第一个语句之前完成具有静态或线程存储持续时间的非局部变量的动态初始化。 If the initialization is deferred to some point in time after the first statement of the initial function of the thread, it shall occur before the first odr-use (3.2) of any variable with thread storage duration defined in the same translation unit as the variable to be initialized. 如果初始化被推迟到线程初始函数的第一个语句之后的某个时间点,它应该在任何变量的第一个odr-use(3.2)之前发生,其中线程存储持续时间与变量在同一个转换单元中定义要初始化。

I assume that "the initial function of the thread" refers to main, and not just threads started with std::thread. 我假设“线程的初始函数”是指main,而不仅仅是以std :: thread开头的线程。

h1.h h1.h

#ifndef H1_H_
#define H1_H_

extern int count;

#endif

tu1.cpp tu1.cpp

#include "h1.h"

struct S
{
   S()
   {
      ++count;
   }
};

S s;

tu2.cpp tu2.cpp

#include "h1.h"

int main(int argc, char *argv[])
{
   return count;
}

tu3.cpp tu3.cpp

#include "h1.h"

int count;

So, if a compiler defers dynamic initialization, it seems that footnote 34 states that s must be initialized at some point. 因此,如果编译器推迟动态初始化,脚注34似乎表明必须在某个时刻初始化s Since there are no other variables with dynamic initialization in the translation unit, there is no other variable to odr-use to force initialization of the variables in tu1. 由于在转换单元中没有其他具有动态初始化的变量,因此没有其他变量可用于强制初始化tu1中的变量。 At what point is s guaranteed to have been initialized? 在什么时候被s保证已初始化?

Is main guaranteed to return 1? 主要保证返回1吗? Also, is there some way to change this program such that it is no longer guaranteed to return 1? 还有,有什么方法可以改变这个程序,使其不再保证返回1? Alternatively, if it isn't guaranteed, is there some way to change this program such that it becomes guaranteed? 或者,如果不能保证,有没有办法改变这个程序,以保证它?


I broke the code up so that the definition of s is in a different translation unit from main . 我打破了代码,以便s的定义与main翻译单元不同。 This avoids the question of whether main is odr used. 这避免了main是否使用odr的问题。 Given that s is the only object in the translation unit, is it guaranteed that main will return 1? 鉴于s是翻译单元中唯一的对象,是否保证main将返回1?

I think that all this wording is there to describe what will happen in dynamic loaded libraries, but without explicitly naming them. 我认为所有这些措辞都是为了描述动态加载库中会发生什么,但没有明确命名它们。

To summarize how I interpret it: a non-local variable with static storage duration and dynamic initialization will: 总结我如何解释它:具有静态存储持续时间和动态初始化的非局部变量将:

  1. be initialized before the first odr-use of anything in its translation unit; 在翻译单元中的任何事物的第一次使用之前进行初始化;
  2. possibly, before starting main , but possibly after it. 可能,在开始main之前,但可能在之后。

I interpret the footnote 34 as (but remember that footnotes are not normative): 我将脚注34解释为(但请记住,脚注不是规范性的):

When anything in a TU is ord-used, then every non-local variable with static storage duration having initialization with side-effects must be initialized, even the variables that are not odr-used. 当TU中的任何东西被ord-used使用时,每个具有静态存储持续时间的非局部变量都必须初始化,即使是没有使用过的变量也是如此。

So, if there is a TU where nothing is ord-used, then its dynamic initializations may not happen. 因此,如果存在未使用任何东西的TU,则其动态初始化可能不会发生。

Example

h1.h h1.h

extern int count;
struct S
{
    S();
};

h1.cpp h1.cpp

#include "h1.h"

int count;
S::S()
{
   ++count;
}

h2.cpp h2.cpp

#include "h1.h"
S s;

main.cpp main.cpp中

#include "h1.h"
#include <stdio.h>
int main()
{
    printf("%d\n", count);
}

This could print 0 or 1: since anything in TU h2 is never odr-used, it is unspecified when the code initialization of s will be done, if at all. 这可以打印0或1:因为TU h2中的任何内容都不会被使用,所以当s的代码初始化完成时(如果有的话),它是未指定的。

Naturally, sane compilers will initialize s before main, so it will surely print 1 : 当然,理智的编译器会在main之前初始化s ,所以它肯定会打印1

$ g++ main.cpp h2.cpp h1.cpp -o test1
$ ./test1
1

Now, imagine that h2.cpp is in a shared library: 现在,假设h2.cpp位于共享库中:

$ g++ -shared -fPIC h2.cpp -o h2.so

And the main file is now: 主文件现在是:

main2.cpp main2.cpp

#include "h1.h"
#include <dlfcn.h>
#include <stdio.h>

int main()
{
    printf("%d\n", count);
    dlopen("./h2.so", RTLD_NOW);
    printf("%d\n", count);
    return 0;
}

Compile and run: 编译并运行:

$ g++ -shared -fPIC h2.cpp -o h2.so
$ g++ -rdynamic main.cpp h1.cpp -ldl -o test2
$ ./test2
0
1

See? 看到? The initialization of s has been delayed! s的初始化已被延迟! The nice part is that it is impossible to reference anything in the dynamic loaded library without first loading it, and loading it will trigger the dynamic initialization. 好的部分是,如果没有先加载它就不可能在动态加载库中引用任何内容,加载它将触发动态初始化。 So all is well. 一切都很好。

If you think that using dlopen is cheating, remember that there are compilers that support delay loading shared libraries (VC++ for example), where the system call to load the library will be generated automatically by the compiler just the first time it is needed. 如果您认为使用dlopen是作弊,请记住有些编译器支持延迟加载共享库(例如VC ++),其中加载库的系统调用将在第一次需要时由编译器自动生成。

Without searching for the right pages in the definition I can say that your program is guaranteed to return 1. Every static or global initialization is done before the first command in the main. 如果不在定义中搜索正确的页面,我可以说保证程序返回1.每次静态或全局初始化都在main中的第一个命令之前完成。 Global variables are initializes first an then the constructors of global objects are executed. 全局变量首先初始化然后执行全局对象的构造函数。 Statics within a function/method scope a initialized before first use. 函数/方法范围内的静态在首次使用之前初始化。 But there is a trap: 但是有一个陷阱:

int count;

struct A
{
   A()
   {
     count=5;
   }
};

struct B
{
   B()
   {
     count=count*2;
   }
};


A a;
B b;

void main(void)
{
  return count;
}

As mentioned in a commentary of Ben Voigt, the result is defined if both instances are create in the same translation unit. 如Ben Voigt的评论中所述,如果两个实例都在同一翻译单元中创建,则定义结果。 So in my sample, the result is 10. If the instances are create in different files (and compiled separately to different .obj files) the result is not defined. 所以在我的示例中,结果是10.如果实例是在不同的文件中创建的(并且分别编译为不同的.obj文件),则不会定义结果。

“在与要初始化的变量相同的翻译单元中定义的任何函数或变量的第一次使用”包括要初始化的变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 静态类成员是否保证在调用`main`之前初始化? - Are static class members guaranteed to be initialized before `main` is called? 当静态变量在同一转换单元中被静态方法使用时,是否保证可以初始化静态变量? - Is static variable guaranteed to be initialized when used by static methods in the same translation unit? 是否保证在孩子的静态变量之前初始化父的静态变量? - Is parent's static variables guaranteed to be initialized before child's static variables? 是否可以确保std :: cout初始化? - Is std::cout guaranteed to be initialized? 在初始化该类的静态对象之前,是否可以保证该类的静态成员的初始化? - Is initialization of static member of a class guaranteed before initialization of a static object of that class? 在Mac OS X上未初始化静态对象 - Static object not initialized on Mac OS X static object 如何在编译时初始化? - How static object gets initialized at compile time? 返回使用braced init list初始化的对象时,我保证会有一对构造函数和析构函数调用吗? - Am I guaranteed a single pair of constructor and destructor calls when returning an object initialized with braced init list? 这里是否保证静态初始化? - Is static initialization guaranteed here? 在地图上 <string, int> ,是否保证int初始化为零? - In map<string, int>, is it guaranteed that the int is initialized to zero?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM