代码示例应该解释一下:
class A
{
B* pB;
C* pC;
D d;
public :
A(int i, int j) : d(j)
{
pC = new C(i, "abc");
} // note pB is not initialised, e.g. pB(NULL)
...
};
显然pB应该明确初始化为NULL以保证安全(并且清晰),但是,就其而言,构造A后pB的值是什么?是否默认初始化(这是零?)或不(即不确定和内存中的任何东西)。我意识到C ++中的初始化有一些规则。
我认为它不是默认初始化的;在Visual Studio中以调试模式运行时,它已将pB设置为指向0xcdcdcdcd - 这意味着内存已经新(在堆上)但未初始化。但是在释放模式下,pB始终指向NULL。这只是偶然的,因此不能依赖;或者这些编译器是否为我初始化(即使它不在标准中)?在Solaris上使用Sun编译器进行编译时,它似乎也是NULL。
我真的在寻找标准的具体参考来说明这种或那种方式。
感谢。
答案 0 :(得分:11)
这是他标准的相关段落:
12.6.2初始化基数和成员[class.base.init]
4如果给定的非静态数据成员或 基类不是由mem-命名的 初始化者ID mem-initializer-list,然后
- 如果实体是非静态数据 成员(可能是合格的) 类类型(或其数组)或基类,以及实体类 是非POD类,该实体是默认初始化的( dcl.init )。 如果实体是const限定类型的非静态数据成员, 实体类应具有用户声明的默认构造函数。
- 否则,实体不是 初始化即可。如果实体是 const限定类型或引用类型,或者(可能是cv-quali- fied)POD类类型(或其数组)包含(直接或 间接地)一个const限定类型的成员,该程序是 生病- 形成。
调用构造函数后 如果成员
,则已完成X类 X中的既未指定 构造函数的mem-initializers,也没有 默认初始化,也未初始化 在执行机构期间 构造函数,成员有 不确定的价值。
答案 1 :(得分:4)
根据C++0x standard第12.6.2.4节,在你的指针变量的情况下,如果你没有将它包含在初始化列表中并且你没有在构造函数的主体中设置它,那么它具有不确定的价值。 0xCDCDCDCD和0是两个可能的值,就像其他任何值一样。 : - )
答案 2 :(得分:1)
我相信这是一个来自古老的C日的神器,当你无法对分配内存包含的内容有所期待时。随着标准进展到C ++,这种“惯例”得以维持。随着C ++编译器的发展,个别作者自己动手解决了这个问题。因此,您的里程可能会因您选择的编译器而异。
“0xcdcdcdcd”看起来是一个易于识别的模式,可以“帮助”调试代码。这就是为什么它不会在发布模式下显示。
我希望这有点帮助,祝你好运。
答案 3 :(得分:0)
未初始化的指针可以指向任何东西。一些编译器供应商会帮助你,让他们指向0或0xcdcdcdcd或其他。
为了确保您的代码安全且可移植,您应该始终初始化您的指针。要么是0,要么是有效值。
e.g。
C* pc = 0;
或
C* pc = new C(...);
如果你总是将指针初始化为0那么这是安全的:
if (!pc)
pc = new C(...);
如果你没有初始化,那么你无法分辨初始化和未初始化的指针。
顺便说一句,C ++中没有像NULL这样的关键字。大多数编译器将NULL定义为0,但使用它并不被认为是可移植的。新的c ++ 0x标准将引入一个新的关键字nullptr,所以当它出现时我们终于有一个可移植的空指针常量。
答案 4 :(得分:0)
pB的值未定义。它可能是也可能不是一致的相同值 - 通常取决于在分配特定A的实例之前在内存中的相同位置。
答案 5 :(得分:0)
未初始化的指针允许基本上包含一个随机值,尽管有些编译器倾向于用0或其他一些可识别的值填充它们,尤其是在调试模式下。
恕我直言,这是由于C ++的“不为你不使用的东西付费”的设计。如果您认为不重要,编译器不需要为您初始化变量。当然,一旦你追逐一个随机指针,你可能会发现下一次初始化它是明智的......答案 6 :(得分:0)
我很少建议您不要了解您正在使用的语言,但在这种情况下,无论pB是否初始化都不是有用的信息。只是初始化它。如果它自动初始化,编译器将优化额外的初始化。如果不是,那么您已经添加了一条额外的处理器指令,并防止了一大堆潜在的错误。