C++ make_shared 用法小结

 更新时间:2025年07月10日 09:13:20   作者:Ring__Rain  
std::make_shared是C++11引入的模板函数,用于创建并管理std::shared_ptr智能指针,具有一定的参考价值,感兴趣的可以了解一下

以下是C++中std::make_shared的用法详解及核心要点,结合实践场景和代码示例说明:

📌 ​一、基本用法与语法​

std::make_shared是C++11引入的模板函数,用于创建并管理std::shared_ptr智能指针,语法如下:

#include <memory>
std::shared_ptr<T> ptr = std::make_shared<T>(构造参数...);

示例​:

class MyClass {
public:
    MyClass(int v) : data(v) {}
private:
    int data;
};
 
int main() {
    auto obj = std::make_shared<MyClass>(42); // 创建对象并初始化
    return 0;
}
  • 作用​:替代new T(...),自动管理内存生命周期,避免手动delete

⚡ ​二、核心优势​

1. ​性能优化(一次内存分配)​​

传统方式​(std::shared_ptr<T>(new T)):
先分配对象内存,再分配控制块(引用计数等),共 ​2次内存分配

​**make_shared​:
将对象和控制块合并为
单次内存分配**,减少内存碎片,提升性能(约30%速度提升)

std::shared_ptr<int> p1(new int(10));   // 2次分配(低效)
auto p2 = std::make_shared<int>(10);    // 1次分配(高效)

2. ​异常安全​

若构造函数抛出异常,make_shared能保证已分配的内存被自动释放,而传统方式可能泄漏:

// 传统方式:若computePriority()抛出异常,new int的内存泄漏
process(std::shared_ptr<int>(new int), computePriority());
 
// make_shared:异常安全
process(std::make_shared<int>(), computePriority()); 

由于make_shared是原子操作,避免了中间状态导致的内存泄漏。

3. ​代码简洁性​

  • 避免显式new,减少代码冗余。

🧩 ​三、实际应用场景​

1. ​共享对象所有权​

多个shared_ptr共享同一对象,引用计数归零时自动释放:

auto obj = std::make_shared<MyClass>();
auto obj2 = obj;  // 引用计数+1
std::cout << obj.use_count(); // 输出2

对象在objobj2均析构后释放。

2. ​解决循环引用​

使用weak_ptr打破循环依赖:

class B; 
class A {
public:
    std::weak_ptr<B> b_ptr; // 弱引用
};
class B {
public:
    std::shared_ptr<A> a_ptr;
};
 
int main() {
    auto a = std::make_shared<A>();
    auto b = std::make_shared<B>();
    a->b_ptr = b; // 弱引用,不增加计数
    b->a_ptr = a; // 强引用
    return 0; // 正确释放资源
}

若使用shared_ptr互相持有会导致内存泄漏。

3. ​高效创建数组(C++20+)​​

// C++20支持make_shared创建数组
auto arr = std::make_shared<int[]>(5); 
arr[0] = 42;

C++11/14需手动构造:std::shared_ptr<int[]>(new int[5])

⚠️ ​四、使用限制与注意事项​

不支持自定义删除器
make_shared无法指定删除器,需直接使用shared_ptr构造函数

auto ptr = std::shared_ptr<FILE>(fopen("file.txt", "r"), [](FILE* f){ fclose(f); });

延迟内存释放问题
对象内存和控制块合并分配后,若存在weak_ptr,则对象内存需等到所有weak_ptr析构才释放(强引用计数为0时仅析构对象,内存块可能未释放)。

适用场景​:对内存敏感的系统需谨慎使用。

私有构造函数限制
若类构造函数为privateprotected,需通过友元或静态工厂函数间接调用make_shared

🛠️ ​五、最佳实践建议​

  • ​**优先使用make_shared**​:除非需要自定义删除器或处理私有构造,否则默认选用。
  • 避免循环引用​:成员指针优先用weak_ptr,尤其父子对象互相引用时。
  • 性能敏感场景​:高频创建对象时(如实时系统),make_shared的性能优势更显著。

💎 ​总结​

std::make_shared是现代C++内存管理的核心工具:

  • 高效​:单次内存分配提升性能;
  • 安全​:异常安全避免泄漏;
  • 简洁​:代码更清晰易维护。
    在共享所有权、资源自动释放及高性能场景中不可或缺,但需注意其内存释放机制和构造限制。

到此这篇关于C++ make_shared 用法小结的文章就介绍到这了,更多相关C++ make_shared内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • 剖析C++编程当中指针作为函数参数的用法

    剖析C++编程当中指针作为函数参数的用法

    这篇文章主要介绍了剖析C++编程当中指针作为函数参数的用法,是C++入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • C++中priority_queue与仿函数实现方法

    C++中priority_queue与仿函数实现方法

    这篇文章主要给大家介绍了关于C++中priority_queue与仿函数实现的相关资料,优先级队列是一种容器适配器,其底层通常采用vector容器,并通过堆算法来维护元素的顺序,文中通过代码介绍的非常详细《》需要的朋友可以参考下
    2024-10-10
  • VC++中图像处理类CBitmap的用法

    VC++中图像处理类CBitmap的用法

    使用VC进行图像处理的时候,CBitmap类为我们提供了丰富的位图处理函数,本文总结了该类的相关函数和常用使用方法,包括加载位图,显示位图,析构CBitmap资源以及在内存中保存位图等内容。
    2015-11-11
  • C++定义和初始化string对象实例详解

    C++定义和初始化string对象实例详解

    这篇文章主要为大家介绍了C++定义和初始化string对象实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • C语言实现单位车辆调度管理

    C语言实现单位车辆调度管理

    这篇文章主要为大家详细介绍了C语言实现单位车辆调度管理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • C语言字符串左旋的两种实现方法

    C语言字符串左旋的两种实现方法

    汇编语言中有一种移位指令叫做循环左移(ROL),下面这篇文章主要给大家介绍了关于C语言字符串左旋的两种实现方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-02-02
  • C语言数据结构实现字符串分割的实例

    C语言数据结构实现字符串分割的实例

    这篇文章主要介绍了C语言数据结构实现字符串分割的实例的相关资料,希望通过本文能帮助到大家实现这样的功能,需要的朋友可以参考下
    2017-10-10
  • 利用Matlab实现时域分析功能的示例详解

    利用Matlab实现时域分析功能的示例详解

    利用MATLAB可以方便地进行控制系统的时域分析。这篇文章主要通过简单的示例为大家介绍了Matlab进行时域分析的具体操作,需要的可以参考一下
    2023-02-02
  • 详解C语言中const关键字的用法

    详解C语言中const关键字的用法

    这篇文章主要对C语言中const关键字的用法进行了详细的分析介绍,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2015-08-08
  • C++多线程互斥锁和条件变量的详解

    C++多线程互斥锁和条件变量的详解

    这篇文章主要为大家详细介绍了C++多线程互斥锁和条件变量,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03

最新评论