c++中如何使用std::make_shared_c++创建共享指针的最佳实践【汇总】

发布时间 - 2026-01-21 00:00:00    点击率:
std::make_shared 是正确写法,不存在 std::make_shared_c++ 等变体;它通过一次内存分配同时创建控制块和对象,更高效安全,但不支持自定义删除器或私有构造函数等场景。

std::make_shared 不存在,正确写法是 std::make_shared

这是最常被拼错的点。C++ 标准库中只有 std::make_shared,没有 std::make_shared_c++ 或类似变体。一旦编译器报错说 “not declared in this scope”,先检查拼写 —— 多半是手误多打了下划线或版本后缀。

为什么优先用 std::make_shared 而不是 new + shared_ptr 构造

std::make_shared 把对象构造和控制块(control block)内存分配合并在一次堆分配中,比分别调用 new 再传给 std::shared_ptr 构造函数更高效,也更安全。

  • 避免异常安全问题:若构造函数抛异常,std::make_shared 能保证控制块与对象内存一起释放;而 std::shared_ptr(new T(args...)) 可能导致 new T 成功但控制块分配失败时的内存泄漏
  • 减少一次内存分配:尤其对小对象,性能提升明显
  • 不支持自定义删除器:如果需要 std::shared_ptr 持有非默认释放逻辑(比如 C 风格资源),就不能用 std::make_shared,必须显式构造

std::make_shared 的参数转发规则和常见陷阱

std::make_shared 使用完美转发(perfect forwarding),所以参数行为和直接调用 T 的构造函数一致 —— 但要注意引用折叠和临时对象生命周期。

  • 传递左值时会被当作左值引用转发,若 T 构造函数只接受右值(如移动构造),会编译失败
  • 不要传入临时字符串字面量给接受 std::string&& 的构造函数:例如 std::make_shared("hello") 中,"hello"const char[6],不是 std::string,不会触发移动,而是调用 std::string(const char*) 构造,没问题;但如果 Foo 构造函数形参是 std::string&& s,则无法绑定字面量
  • 避免在参数中隐式构造大对象:比如 std::make_shared(Heavy()) 会先构造临时对象再移动,不如直接让 Heavy 的构造函数接收初始化参数
auto ptr = std::make_shared>(1000, 42); // ✅ 推荐:直接传 vector 构造参数
auto ptr2 = std::make_shared>(std::vector(1000, 42)); // ❌ 不必要拷贝/移动

不能用 std::make_shared 的典型场景

以下情况必须绕过 std::make_shared,改用 std::shared_ptr 的显式构造:

  • 类有私有或受保护的构造函数,且未将 std:

    :make_shared
    声明为友元(此时编译失败)
  • 需要自定义删除器(如关闭文件描述符、释放 C API 资源):std::shared_ptr(fopen(...), [](FILE* f) { fclose(f); })
  • 需要指向对象的指针不是原始 new 分配的地址(例如 placement new、内存池、mmap 区域)
  • 类重载了 operator new,但你希望控制块和对象分离分配(极少见,通常是为了调试或特殊内存布局)

真正容易被忽略的是:即使你写了 std::make_shared(args...),如果 T 的构造函数本身抛异常,控制块和对象内存仍会由 std::make_shared 自动清理 —— 这部分不用操心;但若你在构造函数里手动 new 了其他资源且没做 RAII 封装,那还是得自己处理。


# ai  # c++  # 标准库  # 为什么  # red  # String  # 封装  # 构造函数  # fopen  # fclose  # const  # 字符串  # char  # 指针  #   # operator  # 形参  # 对象  # this  # 自定义  # 不存在  # 的是  # 这是  # 就不  # 下划线  # 并在  # 这部  # 写了  # 不支持 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Win11怎么设置虚拟桌面 Win11新建多桌面切换操作【技巧】  Claude怎样写约束型提示词_Claude约束提示词写法【教程】  Laravel怎么配置.env环境变量_Laravel生产环境敏感数据保护与读取【方法】  智能起名网站制作软件有哪些,制作logo的软件?  如何实现javascript表单验证_正则表达式有哪些实用技巧  jimdo怎样用html5做选项卡_jimdo选项卡html5实现与切换效果【指南】  SQL查询语句优化的实用方法总结  Laravel如何使用Eloquent进行子查询  如何用美橙互联一键搭建多站合一网站?  如何挑选优质建站一级代理提升网站排名?  Laravel如何配置和使用缓存?(Redis代码示例)  Windows10如何更改计算机工作组_Win10系统属性修改Workgroup  Laravel如何使用Blade组件和插槽?(Component代码示例)  头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?  Laravel如何安装Breeze扩展包_Laravel用户注册登录功能快速实现【流程】  Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧  Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】  JavaScript如何实现类型判断_typeof和instanceof有什么区别  新三国志曹操传主线渭水交兵攻略  Laravel如何实现用户角色和权限系统_Laravel角色权限管理机制  php读取心率传感器数据怎么弄_php获取max30100的心率值【指南】  如何快速搭建高效香港服务器网站?  微博html5版本怎么弄发超话_超话进入入口及发帖格式要求【教程】  javascript日期怎么处理_如何格式化输出  安克发布新款氮化镓充电宝:体积缩小 30%,支持 200W 输出  网站制作壁纸教程视频,电脑壁纸网站?  为什么php本地部署后css不生效_静态资源加载失败修复技巧【技巧】  详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)  Laravel Facade的原理是什么_深入理解Laravel门面及其工作机制  如何在IIS中新建站点并配置端口与物理路径?  Laravel怎么生成URL_Laravel路由命名与URL生成函数详解  中山网站推广排名,中山信息港登录入口?  ,怎么在广州志愿者网站注册?  Laravel怎么实现模型属性的自动加密  Android中AutoCompleteTextView自动提示  浅谈javascript alert和confirm的美化  Laravel如何实现事件和监听器?(Event & Listener实战)  Laravel如何发送邮件_Laravel Mailables构建与发送邮件的简明教程  如何快速启动建站代理加盟业务?  如何用狗爹虚拟主机快速搭建网站?  详解vue.js组件化开发实践  php在windows下怎么调试_phpwindows环境调试操作说明【操作】  Win11怎么关闭专注助手 Win11关闭免打扰模式设置【操作】  Java解压缩zip - 解压缩多个文件或文件夹实例  如何用IIS7快速搭建并优化网站站点?  Windows10怎样连接蓝牙设备_Windows10蓝牙连接步骤【教程】  网站制作软件有哪些,制图软件有哪些?  Laravel辅助函数有哪些_Laravel Helpers常用助手函数大全  如何在云主机上快速搭建多站点网站?  iOS发送验证码倒计时应用