【问题标题】:Uninitialized vector pointer is not NULL [duplicate]未初始化的向量指针不为 NULL [重复]
【发布时间】:2016-03-26 19:43:30
【问题描述】:

在将代码从纯 Windows 平台引入 GNU 编译器的工作中,我注意到一些奇怪的行为,即指向向量的指针未初始化。

对应的代码如下:

typedef vector<IPeer*> Network;
// [...]
Network* m_network;
// [...]
if (m_network == NULL)         // <-- this is the strange part
  m_network = new Network();  

标记的线让我很难过。声明我的向量后,当我在 Windows 机器上编译它时它为 NULL。在使用 GNU Compiler 将代码移动到我的 Mac 之后(我正在使用 g++-5-std=c++11 编译)我的向量在声明后似乎不再为 NULL。标记的行被跳过。

这是一个 c++ 标准实现问题还是这个奇怪的行为来自哪里?

【问题讨论】:

  • @BillLynch 谢谢,这是对我的问题的一个很好的深入解释。

标签: c++ c++11 visual-c++ g++5.1


【解决方案1】:

未初始化的指针具有未确定的行为。可能是 NULL 或不是,取决于编译器(即使对于特定的编译器,ReleaseDebug 二进制文件也可能有不同的行为)和/或内存状态(参见这篇文章的 cmets)。

建议始终初始化它们。永远不要期望一个未初始化的变量有一个特定的值(对于指针来说是正确的,但对于像intbool 这样的其他类型可能会根据编译器/目标采用不同的默认初始化值)。

实际上很难知道单元化变量的值是多少,而且在许多情况下它不是确定性的。

【讨论】:

  • 好的,这真的取决于编译器。谢谢!
  • @Marschal :与 jpo32 所说的相反,它根本不依赖于编译器;它仅取决于实例化变量时该内存位置发生了什么,而这又取决于堆栈的先前内容以及先前执行的代码。在此之前运行的任何代码的更改(包括由于编译器选项而导致的代码生成更改)都可能导致行为的更改。零是一个在计算中经常出现的值,因此该值通常恰好为空——这就是“运气”部分。
  • @Clifford:编译器生成将所有未初始化指针初始化为 null 的代码是完全合法的——或者更有用的是,初始化为一些已知的无效值,例如 (void*)0xDEADBEEF。此外,具有静态存储持续时间的未初始化指针(使用 static 关键字在任何函数之外定义)被初始化为 null。
  • @KeithThompson :好吧,与其说“它根本不依赖于编译器”,不如提醒一下,它可能依赖于编译器,或者它可能完全是不确定的。在我对编译器(主要在嵌入式系统中)的观察中,整个堆栈 被初始化为某个值可能很常见,但不会发生单个局部变量的隐式初始化。因此,在执行早期,局部变量具有确定性值,但当堆栈内存被重用时,它会保留那里留下的任何内容。
  • 感谢你们两位的澄清,我编辑了我的帖子。
【解决方案2】:

本地 POD 变量由隐式初始化。在您的 Windows 实现中,它只是碰巧为 null,而且是危险代码。

使用显式初始化:

Network* m_network = 0 ;

【讨论】:

  • 默认初始化发生,只是对于POD对象,这意味着将内部状态保持为未初始化。 en.cppreference.com/w/cpp/language/default_initialization
  • @BillLynch :我改变了措辞。我的意思是“默认情况下未初始化”而不是“默认初始化”,这在语言定义中当然具有特定含义。
猜你喜欢
  • 1970-01-01
  • 2016-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多