我有一个我能想到的最简单的课程:
class BaseClass { public: int pub; };
然后我有三个同样简单的程序来创建BaseClass对象并打印出他们数据的[未初始化]值.
情况1
BaseClass B1; cout<<"B1.pub = "<<B1.pub<<endl;
打印出:
B1.pub = 1629556548
哪个好.我实际上认为它会被初始化为零,因为它是POD或Plain Old Datatype或类似的东西,但我想不是吗?到现在为止还挺好.
案例2
BaseClass B1; cout<<"B1.pub = "<<B1.pub<<endl; BaseClass B2; cout<<"B2.pub = "<<B2.pub<<endl;
打印出:
B1.pub = 1629556548 B2.pub = 0
这绝对是奇怪的.我以相同的方式创建了两个相同的对象.一个被初始化而另一个没有.
案例3
BaseClass B1; cout<<"B1.pub = "<<B1.pub<<endl; BaseClass B2; cout<<"B2.pub = "<<B2.pub<<endl; BaseClass* pB3 = new BaseClass; cout<<"B3.pub = "<<pB3->pub<<endl;
打印出:
B1.pub = 0 B2.pub = 0 B3.pub = 0
这是最奇怪的.它们都被初始化为零.我所做的只是添加两行代码,它改变了以前的行为.
那么这只是“未初始化的数据导致未指明的行为”的情况,还是“引擎盖下”更合乎逻辑?
解决方法
So is this just a case of ‘uninitialized data leads to unspecified behavior’
是…
有时,如果你调用malloc(或new,它调用malloc),你将获得填充零的数据,因为它位于内核的新页面中.其他时候它将充满垃圾.如果你把一些东西放在堆栈上(即自动存储),你几乎肯定会得到垃圾 – 但它很难调试,因为在你的系统上垃圾可能有点可预测.对于堆栈中的对象,您会发现在完全不同的源文件中更改代码可以更改您在未初始化的数据结构中看到的值.
关于POD:POD是否真的是一个红色的鲱鱼.我只解释了它,因为这个问题提到了POD,并且谈话从那里脱轨了.两个相关概念是存储持续时间和构造函数. POD对象没有构造函数,但是没有构造函数的所有东西都不是POD. (从技术上讲,POD对象没有非平凡的构造函数,也没有非平凡构造函数的成员.)
储存期限:有三种.静态持续时间用于全局变量,自动用于局部变量,动态用于堆上的对象. (这是一种简化,并不完全正确,但如果您需要完全正确的东西,您可以自己阅读C标准.)
具有静态存储持续时间的任何内容都会初始化为零.因此,如果您创建BaseClass的全局实例,那么其pub成员将为零(首先).由于您将它放在堆栈和堆上,因此该规则不适用 – 并且您不会执行任何其他操作来初始化它,因此它未初始化.它恰好包含了最后一段代码留在内存中的垃圾.
通常,堆或堆栈上的任何POD都将是未初始化的,除非您自己初始化它,并且值将是未定义的,当您重新编译或再次运行程序时可能会更改.通常,任何全局POD都将初始化为零,除非您将其初始化为其他内容.
检测未初始化的值:尝试使用Valgrind的memcheck工具,它将帮助您找到使用未初始化值的位置 – 这些通常是错误.