C ++中函数内的静态变量 - 即使函数没有运行也会分配?

时间:2010-05-30 16:06:17

标签: c++ static memory-management

我一直在网上阅读C ++,这是我无法找到答案的一件事。

我知道函数中使用的静态变量类似于全局变量,并且该函数的后续调用将使静态变量在调用之间保持其值。

但是,如果永远不调用该函数,静态变量是否会被分配?

由于

7 个答案:

答案 0 :(得分:16)

如果从未调用该函数,则链接器很可能 deadstrip 函数和静态变量,阻止它进入.rodata.data.bss段(或您的可执行文件格式的等价物)。

但是,有多种原因导致链接器可能没有死区(标志告诉它不能,无法确定取决于符号的内容等)。

值得检查您的链接器映射文件(有时只是一个文本文件!),或者使用最终可执行文件上的objdumpnmdumpbin实用程序来查看符号或相关符号(例如静态初始化代码)幸免于难。

答案 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)

在函数调用期间,类(成员)或函数上定义的静态变量不会在堆栈上动态分配,就像非静态变量一样。它们被分配在为全局和静态数据保留的生成代码的另一个区域中。因此,如果您是否调用该函数,实例化包含静态成员的类,则无论如何都会在程序数据区保留其数据空间。