C++ make_shared 用法

发布于:2025-06-20 ⋅ 阅读:(15) ⋅ 点赞:(0)

以下是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])


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

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

    auto ptr = std::shared_ptr<FILE>(fopen("file.txt", "r"), [](FILE* f){ fclose(f); });
  2. 延迟内存释放问题
    对象内存和控制块合并分配后,若存在weak_ptr,则对象内存需等到所有weak_ptr析构才释放(强引用计数为0时仅析构对象,内存块可能未释放)。

    适用场景​:对内存敏感的系统需谨慎使用。
  3. 私有构造函数限制
    若类构造函数为privateprotected,需通过友元或静态工厂函数间接调用make_shared


🛠️ ​五、最佳实践建议

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

💎 ​总结

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

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

网站公告

今日签到

点亮在社区的每一天
去签到