为何将C++类数据成员改为引用后程序输出异常?
问题解析:引用成员变量导致析构时丢失字符串内容的原因
先给大家还原下场景:
原本的test类中,name是普通的string成员,运行代码后输出完全符合预期:
#include <iostream> #include <string> using namespace std; class test { string name; // non-reference public: test(string name1 = "default") :name (name1) { cout << name << " is constructed"<< endl;} ~test() { cout << name << " is destructed"<<endl;} }; int main() { test t1("Mike"); test t2; }
输出:
Mike is constructed default is constructed default is destructed Mike is destructed
但把name改成引用类型string &name后,析构时的输出就丢了名字:
修改后的类代码:
class test { string &name; // **Make it reference** public: test(string name1 = "default") :name (name1) { cout << name << " is constructed"<< endl;} ~test() { cout << name << " is destructed"<<endl;} };
输出:
Mike is constructed default is constructed is destructed is destructed
核心原因:引用绑定了生命周期极短的局部临时对象
咱们一步步拆解问题:
- 当你调用
test t1("Mike")时,字符串字面量"Mike"会先隐式构造一个临时的string对象,然后构造函数的形参name1(string类型)会拷贝这个临时对象,成为构造函数栈帧里的局部变量。 - 你的引用成员
name直接绑定到了这个局部的name1上。但构造函数执行完毕后,它的栈帧会被销毁,局部变量name1也会被析构——这时候name就变成了悬空引用,指向的对象已经不存在了。 - 等到析构函数执行时,你尝试访问这个悬空引用的
name,这属于C++里的未定义行为,这里刚好表现为输出空字符串,所以只打印出is destructed。
test t2;的情况完全一样:默认参数"default"会构造一个临时string作为形参name1,引用绑定后,构造函数结束name1被析构,析构时引用悬空,自然读不到内容。
对比原代码的正常逻辑
原代码中name是普通的string成员,构造函数里是把name1的值拷贝给name,name成为类对象自己的独立成员,生命周期和类对象完全一致,所以析构时能正常访问并打印名字。
题外话:如果想用引用成员该怎么做?
如果一定要用引用类型的成员,你得确保引用绑定的对象生命周期比类对象更长:
- 比如把构造函数参数改成
const string& name1,并且传入一个全局变量、或者main里的局部变量(生命周期覆盖类对象); - 绝对不能绑定到构造函数的局部形参或者临时对象上,否则必然出现悬空引用的问题。
内容的提问来源于stack exchange,提问作者Alok
相关产品推荐
相关产品推荐

