为什么C++中shared_ptr管理的A类对象在print调用前就被析构?
问题原因分析
核心错误:成员变量被局部变量遮蔽
你在B类的带参构造函数中声明了和成员变量同名的局部变量obj:
B(string s) { cout << "shared_ptr creation" <<endl; shared_ptr<A> obj = make_shared<A>(s); // 这里定义的是构造函数的局部obj,不是类的成员obj cout << "shared_ptr creation done" <<endl; }
- 你创建的
shared_ptr<A>对象仅被这个局部变量持有,构造函数执行结束后局部变量销毁,对应A对象的引用计数降到0,所以直接被析构,这就是A对象在print调用前就销毁的直接原因。 - 类B的成员
obj全程没有被初始化,一直是空shared_ptr。
后续未定义行为
你调用func时采用值传递参数:
void func( B i) { i.print();}
值传递会调用B类的默认拷贝构造函数,把原对象b的空成员obj拷贝给参数i的成员。执行i.print()时对空shared_ptr执行->解引用属于未定义行为:
- 你的运行结果中还能打印
A print called只是巧合,因为A::print()没有访问任何类的成员变量,哪怕this指针为空也没有触发崩溃。如果print函数中访问了str成员,会直接触发段错误。
输出中两次销毁B的原因
你创建了两个B类对象:
- main块中定义的
B b("hello world") - func的值传递参数
B i,是b的拷贝
两个对象分别在离开func作用域、离开main内部块作用域时析构,所以会打印两次destroying B。
修复方案
- 构造函数中直接给成员变量赋值,不要重复声明局部变量,推荐用初始化列表写法:
B(string s) : obj(make_shared<A>(s)) { cout << "shared_ptr creation" <<endl; cout << "shared_ptr creation done" <<endl; }
- 如果不需要修改参数,建议func改为传const引用,避免不必要的拷贝:
void func(const B& i) { i.print();}
修复后A对象的引用计数会被正确持有,直到B对象全部销毁后才会析构A对象,不会出现提前销毁和空指针解引用问题。
内容的提问来源于stack exchange,提问作者Pramod
相关产品推荐
相关产品推荐

