C++中用户定义类型的静态初始化

static initialization of user defined type in C++

本文关键字:静态 初始化 类型 定义 用户 C++      更新时间:2023-10-16

我知道关于什么是静态变量和初始化顺序有很多,这更进一步。

想象一下,在1个CPP中,以下行:

struct A
{
void* a;
size_t b;
};
static bool bMyBoolean = true;
static std::vector<A> myVector;

这里的保证是bMyBooleanmyVector之前被初始化。它们也都是在调用main()之前初始化的
但是,myVector有一个有效的值和内存地址,但在_initterm期间初始化,而bMyboolean较早初始化,在initterm期间不需要初始化调用。

这是因为它似乎是一个原生类型,但我找不到任何关于这种行为的参考或信息。

一点上下文:例如,当我重载malloc,并且为用户定义的类型调用构造函数时,它将进入malloc,但这里的一些静态数据还没有准备好(这是意料之中的,因为翻译单元之间的静态变量没有得到保证),但这意味着我可以安全地访问和更改它,然后它会被重新初始化。

这让我想到了下一个问题,那么这种记忆生活在哪里
重建到位吗
由于正在进行malloc调用,因此会对其进行初始化。这是否意味着本机变量生活在程序启动时分配的静态堆中,而用户定义的类型生活在堆中?

如果是这样的话,如何跟踪被声明为静态的用户定义类型?

这是因为C++标准区分了三种类型的初始化:

  • 零初始化
  • 常量初始化
  • 动态初始化

§3.6.2

  1. 在进行任何其他初始化之前,具有静态存储持续时间或线程存储持续时间的变量应为零初始化。

    执行恒定初始化:

    • 如果出现在具有静态或线程的引用的初始值设定项中的每个完整表达式(包括隐式转换)存储持续时间是一个常量表达式,引用是绑定的指定具有静态存储持续时间的对象的左值或临时的
    • 如果具有静态或线程存储持续时间的对象由构造函数调用初始化,如果该构造函数是constexpr构造函数,如果所有构造函数参数都是常量表达式(包括转换),如果在函数调用替换之后mem初始化器和中的构造函数调用和完整表达式非静态数据成员的大括号或相等的初始值设定项是常量表达式
    • 如果具有静态或线程存储持续时间的对象没有由构造函数调用初始化,并且如果在其初始值设定项中出现的是一个常量表达式

    零初始化和常量初始化一起被调用静态初始化;所有其他初始化都是动态的初始化。在任何进行动态初始化。

您所说的是常量初始化(静态初始化的一部分),它不限于内置类型。

如果您想了解更多信息,请熟悉标准的3.6.2部分:"非局部变量的初始化">


[…],但这意味着我可以安全地访问和更改它,然后它会被重新初始化。

当然-只要操作系统允许,你总是可以修改特定内存位置下的内容。把它想象成新的放置-有一个为这样的对象分配的内存,但在初始化阶段会调用构造函数。因此它被初始化为"就位"。

这是否意味着本地变量生活在程序启动时分配的静态堆中,而用户定义的类型生活在堆上?

否。变量的类型和它的位置之间并没有直接的联系。局部变量被放置在堆栈上,动态(通过malloc()/new分配)被放置在堆内,静态被放置在映像内(例如MyApp.exe)。在应用程序执行后,它被加载到内存中,包括所有具有静态存储的对象,此时为其保留内存。只要main()正在运行,您就可以认为这些对象是有效的。

您的文章中有四个问题。然而,我有一种预感,您主要关心的是,在运行时环境初始化某些static对象之前,这些对象的状态会被malloc修改。

最好不要依赖全局static变量的初始化顺序。

如果malloc需要修改某些static数据,最好通过函数提供对这些数据的访问。

代替:

static std::vector<A> myVector;

使用

static std::vector<A>& getVector()
{
static std::vector<A> myVector;
return myVector;
}

如果这样做,myVector就保证在函数返回时被初始化。

bMyBooleanmyVector都位于静态存储中,总共贡献了sizeof(bool) + sizeof(std::vector<A>)个字节。静态存储在图像文件本身中,比如app.exe。当您执行app.exe时,Windows会将映像文件加载(映射)到为新进程生成的虚拟内存地址中,也就是说,当最初"死"的静态存储变为活动时。系统稍后在app.exe中运行代码,其中包括在myVector上调用std::vector<A>的构造函数。也就是说,在myVector的静态存储器上。还记得this指针吗?传递给构造函数的this指针将指向myVector的静态存储。然后,构造函数分配的内存是动态的并且在堆上。指向该动态存储器的指针存储在myVector的静态存储器中。

我建议你阅读更多关于链接和加载的内容。