C ++中用户定义类型的静态初始化
static initialization of user defined type in C++
我知道有很多关于什么是静态变量和初始化顺序的内容,这更进一步。
假设在 1 CPP 中,以下行:
struct A
{
void* a;
size_t b;
};
static bool bMyBoolean = true;
static std::vector<A> myVector;
这里保证bMyBoolean
在myVector
之前初始化。
它们也在 main()
被调用之前被初始化。
但是,myVector
具有有效值和内存地址,但在 _initterm 期间被初始化,而 bMyboolean
更早初始化并且在 initterm 期间不需要初始化调用。
这是因为它看起来是原生类型,但我找不到关于此行为的任何参考资料或信息。
一些上下文:例如,当我重载 malloc
时,并且为用户定义类型调用构造函数时,它将进入 malloc
,但这里的一些静态数据不是准备好了(这是预期的,因为不能保证翻译单元之间的静态变量)但这意味着我可以安全地访问和更改它,然后它会被重新初始化。
这让我想到了下一个问题,那么这段内存存放在哪里?
它会就地重建吗?
由于正在进行 malloc
调用,因此它会被初始化。这是否意味着本机变量位于程序启动时分配的静态堆中,而用户定义的类型位于堆中?
如果是这种情况,您如何跟踪声明为静态的用户定义类型?
那是因为C++标准区分了三种类型的初始化:
- 零初始化
- 常量初始化
- 动态初始化。
§ 3.6.2
Variables with static storage duration or thread storage duration shall be zero-initialized before any other initialization takes place.
Constant initialization is performed:
- if each full-expression (including implicit conversions) that appears in the initializer of a reference with static or thread
storage duration is a constant expression and the reference is bound
to an lvalue designating an object with static storage duration or to
a temporary
- if an object with static or thread storage duration is initialized by a constructor call, if the constructor is a constexpr constructor,
if all constructor arguments are constant expressions (including
conversions), and if, after function invocation substitution, every
constructor call and full-expression in the mem-initializers and in
the brace-or-equal initializers for non-static data members is a
constant expression
- if an object with static or thread storage duration is not initialized by a constructor call and if every full-expression that
appears in its initializer is a constant expression.
Together, zero-initialization and constant initialization are called
static initialization; all other initialization is dynamic
initialization. Static initialization shall be performed before any
dynamic initialization takes place.
你说的是常量初始化(静态初始化的一部分),并不局限于内置类型。
熟悉标准的 3.6.2 部分:"Initialization of non-local variables" 如果您想了解更多。
[...] but it means I can access and alter it safely, and then it gets re-initialized.
当然 - 只要 OS 允许,您随时可以修改特定内存位置下的内容。把它想象成 placement new - 为这样的对象分配了内存,但是在初始化阶段会调用构造函数。于是初始化为"in place".
Does it mean the native variables live in a static heap that is allocated at boot of the program, and the user defined types live on the heap?
没有。变量类型与其位置之间没有直接联系。局部变量放在堆栈上,动态变量(通过 malloc()
/new
分配)位于堆内,静态变量位于映像内(例如 MyApp.exe
)。 app执行后加载到内存中,包括所有静态存储的对象,此时预留内存。只要 main()
是 运行.
,您就可以认为此类对象有效
bMyBoolean
和 myVector
都存在于静态存储中,总共贡献了 sizeof(bool) + sizeof(std::vector<A>)
字节。静态存储在图像文件本身中,比如 app.exe
。当您执行 app.exe
时,Windows 将图像文件加载(映射)到为新进程生成的虚拟内存地址中,这就是最初的 "dead" 静态存储开始活跃的时候。系统稍后运行 app.exe
中的代码,其中涉及在 myVector
上调用 std::vector<A>
的构造函数。即在myVector
的静态存储上。还记得 this
指针吗?传递给构造函数的 this
指针将指向 myVector
的静态存储。构造函数分配的内存是动态的,并且在堆上。指向此动态存储的指针存储在 myVector
.
的静态存储中
我建议您阅读有关链接和加载的更多信息。
您的 post 中有四个问题。但是,我有一种预感,您主要关心的是某些 static
对象的状态在 运行 时间环境初始化这些对象之前被 malloc
修改。
最好不要依赖全局static
变量的初始化顺序。
如果malloc
需要修改某些static
数据,最好通过函数提供对这些数据的访问。
而不是:
static std::vector<A> myVector;
使用
static std::vector<A>& getVector()
{
static std::vector<A> myVector;
return myVector;
}
如果你这样做,myVector
保证在函数 returns.
时被初始化
我知道有很多关于什么是静态变量和初始化顺序的内容,这更进一步。
假设在 1 CPP 中,以下行:
struct A
{
void* a;
size_t b;
};
static bool bMyBoolean = true;
static std::vector<A> myVector;
这里保证bMyBoolean
在myVector
之前初始化。
它们也在 main()
被调用之前被初始化。
但是,myVector
具有有效值和内存地址,但在 _initterm 期间被初始化,而 bMyboolean
更早初始化并且在 initterm 期间不需要初始化调用。
这是因为它看起来是原生类型,但我找不到关于此行为的任何参考资料或信息。
一些上下文:例如,当我重载 malloc
时,并且为用户定义类型调用构造函数时,它将进入 malloc
,但这里的一些静态数据不是准备好了(这是预期的,因为不能保证翻译单元之间的静态变量)但这意味着我可以安全地访问和更改它,然后它会被重新初始化。
这让我想到了下一个问题,那么这段内存存放在哪里?
它会就地重建吗?
由于正在进行 malloc
调用,因此它会被初始化。这是否意味着本机变量位于程序启动时分配的静态堆中,而用户定义的类型位于堆中?
如果是这种情况,您如何跟踪声明为静态的用户定义类型?
那是因为C++标准区分了三种类型的初始化:
- 零初始化
- 常量初始化
- 动态初始化。
§ 3.6.2
Variables with static storage duration or thread storage duration shall be zero-initialized before any other initialization takes place.
Constant initialization is performed:
- if each full-expression (including implicit conversions) that appears in the initializer of a reference with static or thread storage duration is a constant expression and the reference is bound to an lvalue designating an object with static storage duration or to a temporary
- if an object with static or thread storage duration is initialized by a constructor call, if the constructor is a constexpr constructor, if all constructor arguments are constant expressions (including conversions), and if, after function invocation substitution, every constructor call and full-expression in the mem-initializers and in the brace-or-equal initializers for non-static data members is a constant expression
- if an object with static or thread storage duration is not initialized by a constructor call and if every full-expression that appears in its initializer is a constant expression.
Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.
你说的是常量初始化(静态初始化的一部分),并不局限于内置类型。
熟悉标准的 3.6.2 部分:"Initialization of non-local variables" 如果您想了解更多。
[...] but it means I can access and alter it safely, and then it gets re-initialized.
当然 - 只要 OS 允许,您随时可以修改特定内存位置下的内容。把它想象成 placement new - 为这样的对象分配了内存,但是在初始化阶段会调用构造函数。于是初始化为"in place".
Does it mean the native variables live in a static heap that is allocated at boot of the program, and the user defined types live on the heap?
没有。变量类型与其位置之间没有直接联系。局部变量放在堆栈上,动态变量(通过 malloc()
/new
分配)位于堆内,静态变量位于映像内(例如 MyApp.exe
)。 app执行后加载到内存中,包括所有静态存储的对象,此时预留内存。只要 main()
是 运行.
bMyBoolean
和 myVector
都存在于静态存储中,总共贡献了 sizeof(bool) + sizeof(std::vector<A>)
字节。静态存储在图像文件本身中,比如 app.exe
。当您执行 app.exe
时,Windows 将图像文件加载(映射)到为新进程生成的虚拟内存地址中,这就是最初的 "dead" 静态存储开始活跃的时候。系统稍后运行 app.exe
中的代码,其中涉及在 myVector
上调用 std::vector<A>
的构造函数。即在myVector
的静态存储上。还记得 this
指针吗?传递给构造函数的 this
指针将指向 myVector
的静态存储。构造函数分配的内存是动态的,并且在堆上。指向此动态存储的指针存储在 myVector
.
我建议您阅读有关链接和加载的更多信息。
您的 post 中有四个问题。但是,我有一种预感,您主要关心的是某些 static
对象的状态在 运行 时间环境初始化这些对象之前被 malloc
修改。
最好不要依赖全局static
变量的初始化顺序。
如果malloc
需要修改某些static
数据,最好通过函数提供对这些数据的访问。
而不是:
static std::vector<A> myVector;
使用
static std::vector<A>& getVector()
{
static std::vector<A> myVector;
return myVector;
}
如果你这样做,myVector
保证在函数 returns.