C++ 静态(全局)对象的初始化是如何发生的

C++ 静态(全局)对象的初始化是如何发生的,c++,c++11,global-variables,C++,C++11,Global Variables,我试图弄清楚全局对象的构造函数是如何调用的。我知道在使用翻译单元中的任何内容之前都会调用它们,对此我很满意。我试图找出在Linux和Windows(x86和x64)中如何实现这一点 我似乎记得Windows(x86)使用链表进行构建和销毁,但我很难找到关于这方面的任何资源 我已经找到了以下相关主题的材料,但似乎没有任何内容完全涵盖我要寻找的内容 和PE文件格式文件 有人能告诉我找到这些信息的正确方向吗?你认为在使用对象之前必须运行全局构造函数是错误的。基于这个假设,我已经修复了很多bu

我试图弄清楚全局对象的构造函数是如何调用的。我知道在使用翻译单元中的任何内容之前都会调用它们,对此我很满意。我试图找出在Linux和Windows(x86和x64)中如何实现这一点

我似乎记得Windows(x86)使用链表进行构建和销毁,但我很难找到关于这方面的任何资源

我已经找到了以下相关主题的材料,但似乎没有任何内容完全涵盖我要寻找的内容

和PE文件格式文件


有人能告诉我找到这些信息的正确方向吗?

你认为在使用对象之前必须运行全局构造函数是错误的。基于这个假设,我已经修复了很多bug,但事实并非如此。不适用于gcc,也不适用于MSVC,abd当然不适用于XCode

您可以在gcc中指定一个属性((init_priority(X)),以强制执行命令

或msvc的#pragma init_seg({compiler | lib | user |“section name”[,func name]})

使用XCode时,初始化代码按对象文件传递给链接器的顺序运行


我不认为有一个标准,如果有,那么很少有人遵循它。由工具创建者决定如何跟踪初始化的内容和时间

以防您不理解我这里有代码要演示。 SourceA.cpp

#include "stdafx.h"

extern bool DoFunctionB();

class MyClassA {
protected:
    bool bIsInitialized;
    bool bIsBInitialized;
public:
    MyClassA () : bIsInitialized(true) {
        bIsBInitialized = DoFunctionB();
    }

    bool IsInitialized() {
        return bIsInitialized;
    }
};


static MyClassA MyClassGlobal;

bool DoFunctionA() {
    return MyClassGlobal.IsInitialized();
}
SourceB.cpp

#include "stdafx.h"

extern bool DoFunctionA();

class MyClassB {
protected:
    bool bIsInitialized;
    bool bIsAInitialized;
public:
    MyClassB () : bIsInitialized(true) {
        bIsAInitialized = DoFunctionA();
    }

    bool IsInitialized() {
        return bIsInitialized;
    }
};


static MyClassB MyClassGlobal;

bool DoFunctionB() {
    return MyClassGlobal.IsInitialized();
}
Main.cpp

#include "stdafx.h"

extern bool DoFunctionA();
extern bool DoFunctionB();

int _tmain(int argc, _TCHAR* argv[])
{
    bool a = DoFunctionA();
    bool b = DoFunctionB();
    return 0;
}
将这些添加到新的windows控制台应用程序。在构造函数和DoFunctionX()代码中放置断点。点击F11,并通过它的步骤。您将看到,在初始化另一个cpp文件中的静态对象之前,首先调用的全局初始值设定项将使用该文件中的dof函数

不管你认为标准是什么。编译器就是这样做的。这是一个你必须关注的危险

如果你在构造器中执行2步,你会看到我已经告诉过你的指针列表


愉快的编码。

不看规范,我怀疑实现完全依赖于编译器,而不是依赖于操作系统。你问这个问题是出于好奇还是(与工作/项目相关)你们认为通过理解这个问题可以解决的问题?我将做一个关于全局变量构造/销毁的演示。作为一部分,我想比较/对比一下标准保证和实现的实际功能。@Joachim Isaksson:它是否依赖于链接器(不依赖于编译器)?我不知道。它可能依赖于操作系统或编译器。PE文件有一个入口点,该入口点在加载(或链接)模块时执行。通过这种方式可以实现全局初始化,但我不确定它是以这种方式实现的。该标准仅规定,在使用翻译单元中的任何内容之前(从外部代码),将初始化翻译单元中的所有全局对象。我知道处理全局对象初始化所涉及的困难,而这不是我所看到的。我所关注的是编译器或ABI如何实现调用全局对象的构造函数和析构函数。你引用的是哪种标准?没有支持该参数的编译器。创建2个翻译单元。在标题中添加2个类声明,并导出该类的静态全局,每个单元1个。在.cpp文件中,添加引用其他units全局静态对象的构造函数代码,并对其调用方法。编译、运行并查看在初始化之前使用的是哪一个。当您在使用它时,但在构造函数中是一个断点,请遍历堆栈,并查看它们是如何初始化的。每个翻译单元都有一个列表,列表被连接在一起,列表被初始化。初始化优先级使您可以控制列表中的内容显示位置。Dan:ISO/IEC 14882:2011中的3.6.2/4“实现定义了在main的第一个语句之前是否对具有静态存储持续时间的非局部变量进行动态初始化。如果初始化延迟到main的第一个语句之后的某个时间点,则应在与待初始化变量相同的转换单元中定义的任何函数或变量的首次odr使用(3.2)之前进行。“如果main不在该单元中,那么您认为在该单元中发现的正在做任何事情的是什么?当然,没有什么不是从该单元外部调用的。这和我说的没什么不同,这里说的是,如果你在main之前没有初始化它,只要你在main中的东西使用它之前初始化它就行了。除了main之外,没有什么可以做的事情不是全局初始化。除了初始化之外,没有任何东西不是从main派生的。