C++实现Complex类:不可改类定义时指针赋值及cout输出问题排查
现有代码能输出正确结果的原因
你现在的程序能正常打印出2和3的结果,完全是栈内存残留导致的巧合,并非代码逻辑正确,核心问题出在带参构造函数的写法上:
- 构造函数内写的
double* _re = new double;,本质是在函数作用域内新定义了一个和类成员同名的局部指针,直接遮蔽了类的私有成员_re,后续对这个变量的赋值操作,完全没有碰到类的成员变量。 - 同理,
double* _im = new double;也是构造函数内的局部变量,和类的_im私有成员毫无关联。 - 由于你从头到尾没有给类的两个指针成员赋过有效初始值,这两个成员是指向随机地址的野指针,内存里存的是栈上遗留的残留数据。刚好当前测试程序的栈布局比较简单,这两个野指针的随机值,刚好落在了构造函数形参re、im所在的栈地址上,因此Display函数解引用这两个野指针时,恰好读到了压栈的实参2和3,才输出了看似正确的结果。
- 这种行为属于C++标准定义的未定义行为,只要更换编译环境、在代码中增加几行栈操作、调整编译优化等级,程序要么输出乱码,要么直接崩溃,没有任何长期稳定性可言。
- 另外你代码中通过
new double申请的堆内存,因为马上被局部指针的赋值覆盖,根本没有被释放,已经产生了内存泄漏。
符合项目要求的构造函数实现
由于规则要求不能修改Complex类的定义,必须使用类内提供的两个double*类型指针成员,正确的赋值逻辑需要满足两个要求:
- 不能将成员指针指向栈上的临时形参(否则构造函数返回后,栈空间被回收,指针会变成悬垂指针)
- 不能在函数内定义和成员同名的局部变量,避免出现成员遮蔽的问题
正确的带参构造函数写法如下:
Complex::Complex(double re, double im) { // 给类成员_re动态分配堆内存 _re = new double; // 将传入的实参值拷贝到申请的堆内存中 *_re = re; // 给类成员_im动态分配堆内存 _im = new double; *_im = im; cout << "Complex::Complex(double re,double im)" << endl; }
实现效果说明:
- 指针成员指向的是独立的堆内存,就算构造函数执行完毕、栈帧销毁,内存中存储的实参值也不会被覆盖,后续Display函数解引用时永远能拿到正确的实部、虚部值。
- 因为类内的指针是动态申请的堆内存,建议补充对应的析构函数,在对象销毁时释放堆内存,避免长期运行产生内存泄漏:
Complex::~Complex() { delete _re; delete _im; // 释放后置空,避免出现野指针 _re = nullptr; _im = nullptr; } - 你现有代码中无参构造函数将指针赋值为0(空指针),如果后续直接对未初始化的对象调用Display(),解引用空指针会直接触发程序崩溃,使用时需要注意增加判空逻辑,或者在无参构造中给指针分配默认值为0的堆内存。
内容的提问来源于stack exchange,提问作者denisxoctavian
相关产品推荐
相关产品推荐

