没有初始化的类对象里有指针成员,为何给对象一个引用就不会出错?
如下代码,把引用注释掉,运行的时候就会中断说:使用了未初始化的变量
但是加上引用后,就可以输出CCCCCCCC
另外,如果给类加个空的构造函数,不要引用也可以输出CCCCCCCC。
请问各位大神,这是什么情况?
引用起了什么作用?空的构造函数又起了什么作用?
#include <iostream>
using namespace std;
class A
{
public:
//A(){}
int * pI;
int i;
};
int main()
{
A a;
//A& b = a;
cout<<a.pI<<endl;
system("pause");
}
[解决办法]
用 vs2010 试了一下,debug 下可以看到楼主说的现象。
看了一下汇编,没用引用或默认构造函数的时候,有一个 __RTC_UninitUse 函数,导致了运行时那个对话框。
加了饮用以后,__RTC_UninitUse 调用就取消了。
难道 vs2010 debug 下的编译逻辑认为使用引用某种程度上相当于初始化了?
虽然主楼程序中注释掉的两句没有一个执行了正确的初始化任务。
[解决办法]
又试了试,发现下面几种用法对应的汇编都不包含 __RTC_UninitUse 的调用,即运行时程序不会出那个为初始化变量的对话框。
#include <iostream>
using namespace std;
struct A
{
int * pI;
int i;
};
int main()
{
A a;
A* b = &a;
cout<<a.pI<<endl;
system("pause");
}
#include <iostream>
using namespace std;
struct A
{
int * pI;
int i;
};
void f (A&) {}
int main()
{
A a;
f(a);
cout<<a.pI<<endl;
system("pause");
}
#include <iostream>
using namespace std;
struct A
{
int * pI;
int i;
};
void f (A*) {}
int main()
{
A a;
//f(&a);
cout<<a.pI<<endl;
system("pause");
}
总结一下,我觉得 vs2010 的逻辑是这样的。
(1) debug 模式下 /RTC 开关打开后,会执行必要的运行时检查,比如为初始化变量的使用。
(2) 具体的实现逻辑是,分配其他变量,用以记录被检测变量是否初始化,如果没有则调用 __RTC_UninitUse 中断程序。
(3) 但是判断某变量初始化是各很复杂的问题。如果只有一个变量 a 的时候,那么对于 a.pI 的初始化只能通过 a 完成,所以只需要检测对 a 的动作即可。但是当引入 a 的引用或指针时,同样的初始化可以通过这些间接的途径完成,因此检查工作就变得复杂了,而且随着这类间接途径的增加,检查的复杂度之迅速变得不可控制的。尤其是怎样检查和到底支持到什么样的复杂度很不容易通过程序量化,基本像个人工智能的复杂过程。所以我猜,vs2010 如果发现存在间接路径(引用或指针)能够影响变量的初始化,则取消对应的检查,因为反正也不可能检测所有路径,索性就干脆别检查了。结果就是加了个引用,貌似 a.pI 就初始化了似的。其实不然,只是 vs2010 太累了,不帮你进行运行时检查了。
[解决办法]
(1) #11 只是我基于一些现象的猜测,看起来有道理,实际上也可能是错误的。
(2) VS 有理由对未初始化的指针变量做检查,即便程序并没有对该指针解引用。in particular, c++11 4.1/1 says:
A glvalue (3.10) of a non-function, non-array type T can be converted to a prvalue. ... if the object is uninitialized, a program that necessitates this conversion has undefined behavior.
避免 UB 是好程序的基本目标之一,VS 作为编译器采取措施帮助程序员无可厚非。
[解决办法]

vs2012是没有问题的,只是pi指针没有初始化的问题,所以输出为0000000,其实个人觉得你这么做没有意义,你得出的结果可能会随着编译器的不同出先不同结果,毕竟指针属于悬浮指针,它的值是不确定的
[解决办法]
个人认为,引用后初始化,显然不如定义初始化(包含构造函数初始化)好。
在最大警告(错误等级下),编译时加警告,
似乎也未尝不可,因为警告,毕竟不是错误,
所以,如果引用后初始化,自然可以不必理会警告;
而有了警告,调试有问题以后,或者比较关注警告,可以在第一时间,找到指针没有初始化的错误。
除非标准另有规定。
[解决办法]
引用必须初始化的! 估计在引用的时候给对象同时初始化了,
对于重新定义了构造函数初始化了对象的,
默认的有问题,这得看默认构造函数怎么搞的了啊,