STL中有一些函数以make_
前缀开头,如std::make_pair
,std::make_shared
,std::make_unique
等。为什么更好的做法是使用它们代替简单地使用构造函数?
auto pair2 = std::pair< int, double >( 1, 2.0 );
auto pair3 = std::make_pair( 1, 2.0 );
std::shared_ptr< int > pointer1 = std::shared_ptr< int >( new int( 10 ) );
std::shared_ptr< int > pointer2 = std::make_shared< int >( 10 );
答案 0 :(得分:17)
除了启用参数演绎的好处(如其他答案中已经提到的),还有其他一些好处。
std::make_pair<T1, T2>
注意不只返回std::pair<T1, T2>
。如果您使用std::ref
传入值,则返回的对不会存储std::reference_wrapper
,它会存储引用。
std::make_shared
可以合并分配。 shared_ptr
需要一些地方来保存诸如refcount,弱指针列表等无法直接存储在shared_ptr
中的内容。这些可以与正在创建的对象组合在一个稍大的块中,而不是在两个单独的块中。
std::make_shared
和std::make_unique
都会确保在抛出异常时不会遗漏任何对象。如果将函数调用为f(std::shared_ptr<int>(new int), std::shared_ptr<int>(new int))
,则编译器可能首先分配两个int
对象,然后构造两个shared_ptr<int>
对象。如果第二个分配失败,并且尚未设置shared_ptr<int>
对象以在销毁时释放内存,则会出现内存泄漏。 std::make_shared
和std::make_unique
合并了int
的分配和std::shared_ptr<int>
在函数调用中的构造,以及int
的另一个分配和std::shared_ptr<int>
的其他构造{1}}在另一个函数调用中。函数调用不能重叠,因此如果第二次分配失败,则已经存在一个将被销毁的共享指针,同时撤消第一次分配。
答案 1 :(得分:6)
虽然这可能是主观的,但这项技术的一个主要好处是:
针对接口编写代码,而不是实现
本质上,函数模板实例化基于您传递的参数执行类型推导,而类模板实例化则不会。因此,您不必像直接实例化类那样传递模板参数。
应该注意的是,这不是关于&#34;保存一些字符&#34;而是关于使代码更通用,并避免与函数调用中的具体类型绑定。
但是,情况并非总是如此,正如您的std::make_shared
示例所示,仍然存在必须将类型作为模板参数传递的情况。但是,正如Herb Sutter points out一样,在使用std::make_shared
时还有其他一些优点:
你应该首先写清楚和正确,std::make_shared
实现这两者(主观,但我同意)
使用std::make_shared
更有效率,因为它一次性分配您的对象以及shared_ptr
对象,从而允许更低的分配开销和更好的缓存对齐。
答案 2 :(得分:1)
make_unique
隐藏了你的“原始”指针,这通常是一件好事 - 它不易出错。
make_shared
可以改善shared_ptr<X>
个实例的内存分配。通常,当您使用shared_ptr<X>
构造函数时,它将分配内存两次,首先是X
,第二次是内部数据(例如引用计数器)。 make_shared
启用优化 - 它将创建包含X
和引用计数器的单个内部结构,因此它将执行单个内存分配。和之前一样,它隐藏了原始指针。