我一直在网上阅读C ++,这是我无法找到答案的一件事。
我知道函数中使用的静态变量类似于全局变量,并且该函数的后续调用将使静态变量在调用之间保持其值。
但是,如果永远不调用该函数,静态变量是否会被分配?
由于
答案 0 :(得分:16)
如果从未调用该函数,则链接器很可能 deadstrip 函数和静态变量,阻止它进入.rodata
,.data
或.bss
段(或您的可执行文件格式的等价物)。
但是,有多种原因导致链接器可能没有死区(标志告诉它不能,无法确定取决于符号的内容等)。
值得检查您的链接器映射文件(有时只是一个文本文件!),或者使用最终可执行文件上的objdump
,nm
或dumpbin
实用程序来查看符号或相关符号(例如静态初始化代码)幸免于难。
答案 1 :(得分:8)
C ++标准,第6.7节说:
所有的零初始化(8.5) 具有静态存储的本地对象 持续时间(3.7.1)之前执行 发生任何其他初始化。 POD类型(3.9)的本地对象 静态存储持续时间初始化 用常量表达式 在第一个块之前初始化 进入。一个实现是 允许尽早进行 初始化其他本地对象 静态存储持续时间 与实施相同的条件 允许静态初始化 具有静态存储持续时间的对象 在命名空间范围(3.6.2)。除此以外 这样的对象被初始化了 第一次控制通过它 宣言;这样的对象是 考虑初始化 完成初始化。
这表示本地静态对象通常在控制流第一次遇到它们时初始化。但是,它们可能在此之前被分配 - 除了参考静态对象生命周期之外,标准对静态存储实际上有些保持沉默。
答案 2 :(得分:4)
C ++中的每个对象都有两个与之关联的嵌套时间段:存储持续时间和生存期。 存储持续时间是分配对象占用的原始内存的时间段。 生命周期是构建和销毁该内存中实际对象之间的时间段。 (对于POD类型的构造 - 破坏要么无关紧要,要么不适用,因此它们的生命周期与其存储持续时间相匹配。)
当有人说“已分配”时,他们通常会提到存储时间。该语言实际上并未准确指定对象的存储持续时间何时开始。要求在对象的生命周期开始之前的某个时刻开始就足够了。
因此,在一般情况下,函数内定义的静态对象可能永远不会从其生命周期开始,理论上,它的存储持续时间也不必开始。因此,理论上,甚至可能没有“分配”。
实际上,所有具有静态存储持续时间的对象(“全局”,局部静态等)通常都是平等对待的:在程序启动时,它们会在早期被分配一个特定的存储量。
作为补充说明,如果具有静态存储持续时间的本地对象需要进行非平凡的初始化,则在控件第一次通过定义时执行此初始化。所以在这个例子中
void foo() {
static int *p = new int[100];
}
如果永远不调用该函数,则永远不会分配动态数组。如果调用该函数,它将只被分配一次。这看起来不像你在问什么,但我提到这是为了以防万一。
答案 3 :(得分:1)
我确信这将取决于实施。 MSVC的作用是 - 在EXE或DLL的自动数据段中分配静态对象。但是,构造函数仅在第一次执行包含静态的函数时执行。
答案 4 :(得分:0)
是的,实际分配是依赖于编译器的,尽管我认为每个编译器只保留可执行文件的.static段中的空间(或其可执行文件格式中的等效段)。
然而,初始化仅发生执行流遇到静态对象的第一次,并且是标准所要求的。
但请注意,全局静态对象的初始化以不同的方式工作。
您可以在C++ FAQ lite网站上获得几乎所有问题的非常好的答案。
我也喜欢Scott Meyers的“Effective C ++”。
答案 5 :(得分:0)
取决于。如果你的意思是,永远不会调用,因为函数实际上从未被调用过,那么你的编译器可能不会分配它,甚至不会放入函数代码。但是,如果你让它依赖于用户输入,并且用户输入恰好从未出现过,那么它可能会被预先分配。但是,你正在这里的雷区中进行攻击,最好只是假设它始终由时间控件进入引用它的函数创建。
答案 6 :(得分:0)
在函数调用期间,类(成员)或函数上定义的静态变量不会在堆栈上动态分配,就像非静态变量一样。它们被分配在为全局和静态数据保留的生成代码的另一个区域中。因此,如果您是否调用该函数,实例化包含静态成员的类,则无论如何都会在程序数据区保留其数据空间。