You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 05:42:42