使用std::make_shared
相比于直接使用new
和std::shared_ptr
构造函数在内存分配和管理方面更为高效,主要原因如下:
内存分配效率
std::make_shared
通过一次内存分配来同时分配控制块(用于引用计数等)和对象的内存。这种方式减少了内存分配的次数,提高了效率。
auto sp = std::make_shared<int>(10);
这里,std::make_shared
一次性分配了包含控制块和int
对象的内存。
直接使用new
和std::shared_ptr
构造函数
直接使用new
和std::shared_ptr
构造函数通常需要进行两次内存分配,一次用于对象本身,另一次用于控制块。
std::shared_ptr<int> sp(new int(10));
这里,new int(10)
分配了对象的内存,然后std::shared_ptr
构造函数再分配控制块的内存。
内存局部性
由于std::make_shared
将对象和控制块分配在一起,这些内存通常是连续的,能够更好地利用CPU缓存,提高程序的运行效率。
异常安全性
使用std::make_shared
能够确保在对象构造期间如果抛出异常,不会导致内存泄漏。因为对象和控制块的内存是在一次操作中分配的,如果构造对象时抛出异常,分配的内存会自动释放。
auto sp = std::make_shared<int>(10); // 如果在构造int对象时抛出异常,内存会被自动释放
而使用new
和std::shared_ptr
构造函数时,如果在对象构造期间抛出异常,可能会导致内存泄漏,因为new
分配的内存不会被自动释放。
std::shared_ptr<int> sp(new int(10)); // 如果在构造int对象时抛出异常,new分配的内存不会被自动释放
总结
std::make_shared
在内存分配和管理方面更为高效的原因包括:
- 通过一次内存分配同时分配控制块和对象的内存,减少了内存分配的次数。
- 更好的内存局部性,能够更有效地利用CPU缓存。
- 提供更好的异常安全性,防止在对象构造期间发生异常时导致的内存泄漏。