跳转到内容

C++ make_shared

来自代码酷

C++ make_shared 是 C++11 引入的一个标准库函数模板,用于高效地创建和管理 shared_ptr 对象。它是现代 C++ 内存管理的重要工具,能够减少动态内存分配的开销并提高代码安全性。

概述[编辑 | 编辑源代码]

std::make_shared 是一个工厂函数,用于构造一个对象并返回指向它的 std::shared_ptr。与直接使用 std::shared_ptr 构造函数相比,它具有以下优势:

  • **性能优化**:通常只需一次内存分配(对象和控制块合并分配)。
  • **异常安全**:避免因构造参数求值顺序导致的潜在内存泄漏。
  • **代码简洁性**:减少显式 new 的使用。

其函数原型如下:

  
template< class T, class... Args >  
shared_ptr<T> make_shared( Args&&... args );

基本用法[编辑 | 编辑源代码]

以下示例展示如何用 make_shared 创建一个 shared_ptr

  
#include <iostream>  
#include <memory>  

class MyClass {  
public:  
    MyClass(int value) : data(value) {  
        std::cout << "MyClass constructed with value: " << data << std::endl;  
    }  
    ~MyClass() {  
        std::cout << "MyClass destroyed with value: " << data << std::endl;  
    }  
    void print() const { std::cout << "Value: " << data << std::endl; }  
private:  
    int data;  
};  

int main() {  
    auto ptr = std::make_shared<MyClass>(42); // 创建 shared_ptr  
    ptr->print();  
    return 0;  
}

输出:

  
MyClass constructed with value: 42  
Value: 42  
MyClass destroyed with value: 42  

与传统方法的对比[编辑 | 编辑源代码]

传统方式使用 shared_ptr 构造函数:

  
std::shared_ptr<MyClass> ptr(new MyClass(42)); // 需要两次内存分配

make_shared 通常合并对象和控制块的内存分配,效率更高。

内存分配机制[编辑 | 编辑源代码]

make_shared
单次内存分配
对象存储
控制块存储
shared_ptr引用

数学上,若对象大小为 So,控制块大小为 Sc,则:

  • 传统方式:总分配量 = So+Sc(可能不连续)
  • make_shared:总分配量 ≤ So+Sc(连续内存)

实际应用场景[编辑 | 编辑源代码]

容器存储[编辑 | 编辑源代码]

在容器中管理动态对象时,make_shared 可简化代码并提高性能:

  
std::vector<std::shared_ptr<MyClass>> vec;  
vec.push_back(std::make_shared<MyClass>(10));  
vec.push_back(std::make_shared<MyClass>(20));

工厂模式[编辑 | 编辑源代码]

工厂函数返回 shared_ptr 时推荐使用:

  
class Factory {  
public:  
    static std::shared_ptr<MyClass> create(int val) {  
        return std::make_shared<MyClass>(val);  
    }  
};

注意事项[编辑 | 编辑源代码]

1. **自定义删除器**:make_shared 不支持自定义删除器,需直接使用 shared_ptr 构造函数。 2. **大对象延迟释放**:合并分配可能导致对象内存直到所有 weak_ptr 释放后才被回收。 3. **构造函数私有**:若类构造函数私有,需声明 make_shared 为友元。

高级主题[编辑 | 编辑源代码]

异常安全保证[编辑 | 编辑源代码]

以下代码可能因异常导致内存泄漏:

  
foo(std::shared_ptr<MyClass>(new MyClass(42)), bar()); // 若 bar() 抛出异常

改用 make_shared 可避免:

  
foo(std::make_shared<MyClass>(42), bar()); // 安全

与 allocate_shared 的关系[编辑 | 编辑源代码]

std::allocate_shared 允许自定义分配器,适用于特殊内存池场景。

总结[编辑 | 编辑源代码]

std::make_shared 是现代 C++ 中创建 shared_ptr 的首选方法,兼顾性能与安全性。初学者应优先掌握其基本用法,高级用户可进一步探索其内存模型和异常安全特性。