std::make_shared
是 C++ 标准库中的一个函数模板,用于简化智能指针 std::shared_ptr
的创建过程。引入 std::make_shared
的主要原因是提高代码的安全性、性能和可读性。以下是详细分析:
1. 安全性提升
避免显式调用 new
导致的错误
在不使用 std::make_shared
的情况下,我们通常手动调用 new
来分配内存并初始化对象:
std::shared_ptr<MyClass> ptr(new MyClass(arg1, arg2));
这种方式容易引发以下问题:
- 异常安全问题:如果在
new
和std::shared_ptr
构造之间抛出异常,会导致资源泄漏。 - 内存管理错误:手动调用
new
容易忘记释放资源。
使用 std::make_shared
后,这些问题都被封装到函数内部,减少了手动操作的可能性:
auto ptr = std::make_shared<MyClass>(arg1, arg2);
避免显式分配内存导致的错误
std::make_shared
内部会同时完成内存分配和对象构造,确保两者是一致的。而直接使用 std::shared_ptr(new T)
可能会出现分配内存失败但对象已经构造完成的情况,从而导致内存泄漏。
2. 性能优化
减少一次内存分配
普通方式创建 std::shared_ptr
时,通常需要两次内存分配:
- 分配一块内存存储
std::shared_ptr
的控制块(包含引用计数等元信息)。 - 分配另一块内存存储实际的对象。
而 std::make_shared
将这两块内存合并成一次分配,提高了内存分配效率。这尤其在频繁创建对象时会有显著的性能提升。
缓存局部性
由于 std::make_shared
将控制块和对象存储在一起,访问控制块时的缓存命中率更高,从而提升了程序的整体性能。
3. 提高代码可读性和简洁性
使用 std::make_shared
可以使代码更加简洁和直观:
// 普通方式
std::shared_ptr<MyClass> ptr(new MyClass(arg1, arg2));
// 使用 make_shared
auto ptr = std::make_shared<MyClass>(arg1, arg2);
后者不仅减少了代码量,还避免了重复书写 new
,使代码更易于阅读和维护。
4. 示例对比
普通方式
std::shared_ptr<int> ptr(new int(42)); // 显式调用 new
*ptr = 10; // 修改对象
使用 make_shared
auto ptr = std::make_shared<int>(42); // 自动分配和构造
*ptr = 10; // 修改对象
可以看到,std::make_shared
的语法更加简洁且不易出错。
5. 总结
std::make_shared
的优点包括:
- 提高安全性(避免资源泄漏和异常问题)。
- 提高性能(减少内存分配次数,提高缓存命中率)。
- 提高代码可读性和简洁性。
因此,在现代 C++ 编程中,推荐优先使用 std::make_shared
来创建 std::shared_ptr
。