C++中shared_ptr传递至Wrapper构造函数的问题及正确实现
问题解答
你的猜测完全正确
在Case1中,std::shared_ptr<Wrapped> wrapped是make_Wrapper函数内的局部变量,当函数执行完毕退出时,这个智能指针会被销毁。由于它是指向Wrapped对象的最后一个shared_ptr,会触发你传入的自定义销毁器std::mem_fun(&Wrapped::destroy),最终调用delete this销毁Wrapped对象。
而你的Wrapper结构体中存储的是Wrapped& wrapped_——一个引用,它指向的是已经被销毁的内存空间,后续访问wrapped_.nz_自然会读到垃圾值。
Case2能正常工作,是因为你用裸指针创建Wrapped对象后,没有主动释放它,对象的内存直到程序结束才会被回收,所以在main函数中访问时对象还存在。
正确的实现方式
要通过shared_ptr正确传递对象,核心是让Wrapper也持有std::shared_ptr<Wrapped>,绑定两者的生命周期,确保Wrapped对象在Wrapper还存在时不会被销毁。修改后的代码如下:
#include <iostream> #include <memory> #include <functional> struct Wrapped { int nz_; Wrapped(int nz):nz_(nz) {} // 若没有特殊释放逻辑,这个自定义destroy可以移除,让shared_ptr默认调用delete即可 inline virtual void destroy() { delete this; }; }; struct Wrapper { // 将引用改为shared_ptr,共享Wrapped对象的所有权 std::shared_ptr<Wrapped> wrapped_; // 构造函数接收shared_ptr,用move减少拷贝开销 Wrapper(std::shared_ptr<Wrapped> wrapped):wrapped_(std::move(wrapped)){} inline virtual void destroy() { delete this; }; void print() { std::cout << "from wrapper: wrapped_.nz_=" << wrapped_->nz_<<std::endl; } }; Wrapped* make_Wrapped(int nz) { return new Wrapped(nz); } Wrapper* make_Wrapper(int nz) { std::shared_ptr<Wrapped> wrapped(make_Wrapped(nz), std::mem_fun(&Wrapped::destroy)); std::cout<<" from make_Wrapper "<<wrapped->nz_<<std::endl; // 将shared_ptr传递给Wrapper,共享所有权 return new Wrapper(std::move(wrapped)); } int main() { int nz=10; char tempbuffer[80]; std::shared_ptr<Wrapper> outside_wrapper(make_Wrapper(nz), std::mem_fun(&Wrapper::destroy)); outside_wrapper->print(); std::cout << "Enter something to continue ..." << std::endl; std::cin >> tempbuffer; return 0; }
关键修改点:
- 将
Wrapper中的Wrapped& wrapped_改为std::shared_ptr<Wrapped> wrapped_,让Wrapper持有Wrapped对象的共享所有权 - 调整
Wrapper的构造函数,接收std::shared_ptr<Wrapped>类型的参数,通过std::move避免不必要的拷贝(直接拷贝shared_ptr开销也极小) - 此时
make_Wrapper中的shared_ptr在传递给Wrapper后,所有权被共享,函数退出时局部的shared_ptr销毁不会触发Wrapped对象的释放,直到main中的outside_wrapper销毁,Wrapper的shared_ptr也随之销毁,才会释放Wrapped对象
内容的提问来源于stack exchange,提问作者NNN
相关产品推荐
相关产品推荐

