全局对象内的内置类型的成员变量是不是已初始化为零?

Posted

技术标签:

【中文标题】全局对象内的内置类型的成员变量是不是已初始化为零?【英文标题】:Is a member variable of built-in type inside a global object zero initialised?全局对象内的内置类型的成员变量是否已初始化为零? 【发布时间】:2017-12-21 17:45:58 【问题描述】:

使用具有自动存储持续时间的内置类型的未初始化对象是未定义的行为。当然,我强烈建议始终在类类型中初始化内置类型的成员变量。尽管如此,我假设没有初始化器的内置类型的成员总是初始化为零,如果类类型的相应对象具有静态存储持续时间(即全局目的)。我的假设是,具有静态存储持续时间的类类型对象的完整内存清零

例子:

#include <iostream>
using namespace std;

class Foo 
public:
        int bar;
;

Foo a;

int main() 
        Foo b;
        cout << "a.bar " << a.bar << "\n";
        cout << "b.bar " << b.bar << "\n";
        return 0;

编译:

$ g++ -o init init.cpp -Wall -pedantic # gcc 7.2.1
init.cpp: In function ‘int main()’:
init.cpp:14:31: warning: ‘b.Foo::bar’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  cout << "b.bar " << b.bar << "\n";
                               ^~~~

GCC 只抱怨具有自动存储持续时间 b.bar 而不是 a.bar 的类类型对象的成员。所以我是对的?

请随时修改此问题的标题。

谢谢

【问题讨论】:

零初始化。还有 nmdv,顺便说一句。 " 我的假设是,类类型对象的完整内存在 BSS 中" - C++(和 C)对 BSS 无话可说。 @StoryTeller:谢谢发现这个带有“零初始化”en.cppreference.com/w/cpp/language/zero_initialization,它声明“如果 T 是非联合类类型,所有基类和非静态数据成员都是零初始化的,并且所有填充都初始化为零位。构造函数(如果有)将被忽略。但是“nmdv”是什么意思? 不是我的反对票。当我发表评论时出现 -1 时,我感到很害怕。虽然从那以后它似乎已经被逆转了。 @R Sahu:链接的问题尤其不能处理上述情况。 【参考方案1】:

正如评论中所说,它是零初始化,[basic.start.init]/3:

具有静态存储持续时间([basic.stc.static])或线程存储持续时间([basic.stc.thread])的变量应为零-initialized ([dcl.init]) 在任何其他初始化发生之前。[...]

零初始化一个对象,零初始化它的所有非静态数据成员和填充位,[dlc.init]/6.2:

零初始化 T 类型的对象或引用意味着:[...]

如果 T 是(可能是 cv 限定的)非联合类类型,则每个非静态数据成员和每个基类子对象都是零初始化,并且填充被初始化为零位; [...]

所以,正如你所说,整个对象内存被清零(属于其值表示的位及其填充位)。

【讨论】:

对象零初始化的结果不一定与将其所有位设置为零相同。 (我使用了一个平台,其中空指针的自然表示将前 16 位设置为 0x0FFF - 这将是零初始化指针的结果。)【参考方案2】:

不初始化具有自动存储持续时间的内置类型的对象是未定义的行为。

不,这是不正确的。见[dcl.init]/12:

如果没有为对象指定初始化程序,则该对象是默认初始化的。当获得具有自动或动态存储持续时间的对象的存储时,该对象具有一个不确定的值,如果没有对该对象执行初始化,该对象将保留一个不确定的值,直到该值被替换([expr.ass])。 [ 注意:具有静态或线程存储持续时间的对象是零初始化的,请参阅[basic.start.static]。 — 尾注] 如果评估产生不确定的值,则行为未定义,但以下情况除外:

Foo b; 是已定义的行为,cout &lt;&lt; "b.bar " &lt;&lt; b.bar &lt;&lt; "\n";(在b.bar 具有设定值之前)是未定义的行为。

GCC 只抱怨具有自动存储持续时间 b.bar 而不是 a.bar 的类类型对象的成员。

GCC 与未初始化变量相关的警告系列是为了方便而提供的,并且通常包含误报。在一般情况下,不可能对每种情况都有准确的警告(这与解决停机问题一样难)。它只是让您知道您正在尝试使用您未明确初始化的值,即具有不确定的值,这可能不是您想要的。

【讨论】:

以上是关于全局对象内的内置类型的成员变量是不是已初始化为零?的主要内容,如果未能解决你的问题,请参考以下文章

默认初始化值初始化

C#中static静态变量的用法

列表初始化是不是将原子初始化为零?

为啥在默认成员初始化时内置类型的零成员? [复制]

将多态成员变量实例化为适当的类型

C语言 | 每日基础