当你比较 std::shared_ptr<int> ptr(new int(10));
的方式和使用 std::make_shared<int>(10)
的方式来创建智能指针时,主要有几点不同:
1. 内存分配
std::shared_ptr<int> ptr(new int(10));
:这种方法会进行两次内存分配。首先,new int(10)
为int
分配内存。然后,在创建shared_ptr
对象时,还会为其控制块分配内存。控制块是用来存储引用计数和其他元数据的。std::make_shared<int>(10)
:这种方法通常只进行一次内存分配。std::make_shared
会同时为对象的值和控制块分配一块连续的内存。这不仅可以提高内存分配的效率,还有可能减少程序的总内存占用,因为它减少了内存分配的次数,并且可能更好地利用缓存。
2. 异常安全性
std::shared_ptr<int> ptr(new int(10));
:这种初始化方式在某些情况下可能会导致内存泄漏。如果在new int(10)
和std::shared_ptr
构造函数之间抛出异常(虽然这里的场景不太可能,但在更复杂的情况下可能会发生),那么已分配的内存就会泄漏。std::make_shared<int>(10)
:使用std::make_shared
可以提高异常安全性,因为内存分配和对象构造是作为一个原子操作完成的。这意味着不会在对象的构造和其包装在智能指针中间出现异常泄漏风险。
3. 性能
由于 std::make_shared
只需要一次内存分配,它通常提供更好的性能,特别是在频繁创建和销毁小对象的场景中。减少内存分配的次数不仅减少了内存使用的开销,还可能减少了内存碎片化,从而提高整体性能。
4. 引用计数的内部表现
使用 std::make_shared
创建的 shared_ptr
有一个优化,即对象和控制块存储在同一块连续的内存中。这意味着访问对象或修改引用计数时的缓存效率可能更高。然而,这也意味着即使最后一个 shared_ptr
被销毁,对象占用的内存只有在最后一个 weak_ptr
也消失时才会被释放,这可能会导致较长时间的内存占用。
结论
尽管直接使用 new
的方法在某些特殊情况下可能是必要的,std::make_shared
通常是创建 shared_ptr
的更优选择,因为它提供了更好的性能、安全性和内存使用效率。