为什么使用std :: make_*而不是构造函数更好?

p.i*_*.g. 19 c++ std c++11

有些情况下,与启动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 );
Run Code Online (Sandbox Code Playgroud)
  • 我只是看到这些函数使代码变得更短,但这就是全部吗?
  • 还有其他优点吗?
  • 这些功能更安全吗?

小智 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_sharedstd::make_unique如果抛出异常,两者都要确保没有任何对象遗留下来.如果将函数调用为f(std::shared_ptr<int>(new int), std::shared_ptr<int>(new int)),则编译器可能首先分配两个int对象,然后构造两个shared_ptr<int>对象.如果第二次分配失败,并且shared_ptr<int>尚未设置任何对象以在销毁时释放内存,则会出现内存泄漏.std::make_sharedstd::make_unique结合的分配int和建设std::shared_ptr<int>中的一个函数调用,以及其他配置int和其他建筑std::shared_ptr<int>在另一个函数调用.函数调用不能重叠,因此如果第二次分配失败,则已经存在一个将被销毁的共享指针,同时撤消第一次分配.

  • `make_`智能指针还可以通过消除未配对的`new`来启用"every`new`与`delete`"完整性检查. (3认同)

nas*_*-sh 6

虽然这可能是主观的,但这项技术的一个主要好处是:

编写针对接口的代码,而不是实现

本质上,函数模板实例化基于您传递的参数执行类型推导,而类模板实例化则不会.因此,您不必像直接实例化类那样传递模板参数.

应该注意的是,这不是关于"保存一些字符",而是关于使代码更通用,并避免与函数调用中的具体类型绑定.

但是,情况并非总是如此,正如您的std::make_shared示例所示,仍然存在必须将类型作为模板参数传递的情况.但是,正如Herb Sutter指出的那样,在使用时还有其他几个优点std::make_shared:

  1. 你应该首先写清楚和正确,并std::make_shared实现这两者(主观,但我同意)

  2. 使用std::make_shared更高效,因为它shared_ptr一次性分配您的对象以及对象,从而允许更低的分配开销和更好的缓存对齐.