面试题:C++ 中为什么要引入 make_shared?它有什么优点?

std::make_shared 是 C++11 引入的一个工具函数,用于创建并返回一个 std::shared_ptr,它封装了动态内存分配和 std::shared_ptr 的构造过程。

引入 std::make_shared 的主要目的是为了提高代码的安全性、性能和可读性。


为什么要引入 std::make_shared

在 C++11 之前,创建 std::shared_ptr 通常需要显式地使用 new 分配内存,然后将指针传递给 std::shared_ptr 的构造函数。这种方式存在一些问题:

  1. 代码冗余:需要显式地使用 new 和 std::shared_ptr,代码不够简洁。
  2. 潜在的内存泄漏风险:如果在 new 和 std::shared_ptr 构造之间发生异常,可能会导致内存泄漏。
  3. 性能开销std::shared_ptr 需要维护一个控制块(用于引用计数等),如果单独使用 new 和 std::shared_ptr,会导致两次内存分配(一次是对象本身,一次是控制块)。

std::make_shared 的引入解决了这些问题。


std::make_shared 的优点

  1. 代码简洁性
    • std::make_shared 将内存分配和 std::shared_ptr 的构造合并为一个步骤,代码更简洁。
  2. 异常安全
    • 使用 new 的方式可能在分配内存和构造 std::shared_ptr 之间发生异常,导致内存泄漏。
    • std::make_shared 是原子操作,避免了这种风险。
  3. 性能优化
    • std::make_shared 通常会一次性分配内存,既存储对象又存储控制块,减少了内存分配的次数。
    • 单独使用 new 和 std::shared_ptr 会导致两次内存分配(对象和控制块),而 std::make_shared 只需要一次。
  4. 减少内存碎片
    • 由于 std::make_shared 将对象和控制块分配在连续的内存区域,可以减少内存碎片。

使用示例

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass(int value) : value_(value) {
        std::cout << "MyClass constructed with value: " << value_ << std::endl;
    }
    ~MyClass() {
        std::cout << "MyClass destroyed with value: " << value_ << std::endl;
    }
private:
    int value_;
};

int main() {
    // 使用 make_shared 创建 shared_ptr
    auto ptr = std::make_shared<MyClass>(42);
    std::cout << "Use count: " << ptr.use_count() << std::endl;
    return 0;
}

输出:

MyClass constructed with value: 42
Use count: 1
MyClass destroyed with value: 42

注意事项

  1. 不支持自定义删除器
    • std::make_shared 不支持自定义删除器。如果需要自定义删除器,必须直接使用 std::shared_ptr 的构造函数。
  2. 对象和控制块的生命周期绑定
    • std::make_shared 将对象和控制块分配在连续的内存区域,因此即使对象的引用计数归零,控制块的内存也不会立即释放,直到所有弱引用(std::weak_ptr)也被释放。
  3. 不适合用于大对象
    • 如果对象非常大,且需要提前释放内存,使用 std::make_shared 可能会导致内存占用时间过长。

总结

  • std::make_shared 的主要优点是代码简洁、异常安全和性能优化。
  • 它通过一次性分配内存(对象和控制块)减少了内存分配次数和内存碎片。
  • 适用于大多数需要 std::shared_ptr 的场景,但在需要自定义删除器或特殊内存管理时,可能需要直接使用 std::shared_ptr 的构造函数。

这个问题考察的是对 C++ 智能指针和内存管理的理解,尤其是 std::make_shared 的设计初衷和优势。

THE END
点赞9 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容