【问题标题】:Why is it better to use std::make_* instead of the constructor?为什么使用 std::make_* 而不是构造函数更好?
【发布时间】:2015-09-22 18:59:12
【问题描述】:

STL 中有一些以make_ 前缀开头的函数,如std::make_pairstd::make_sharedstd::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 );
  • 我只是看到这些函数使代码更短,但仅此而已吗?
  • 还有其他优势吗?
  • 这些功能使用起来更安全吗?

【问题讨论】:

标签: c++ c++11 std


【解决方案1】:

除了启用论据推导的好处(正如其他答案中已经提到的)之外,还有一些其他好处。

std::make_pair&lt;T1, T2&gt; 注意不要简单地返回std::pair&lt;T1, T2&gt;。如果您使用std::ref 传入一个值,那么返回的对将不会存储std::reference_wrapper,它将存储一个引用。

std::make_shared 可以组合分配。 shared_ptr 需要一些地方来保存不能直接存储在 shared_ptr 中的引用计数、弱指针列表等内容。这些可以与正在创建的对象组合在一个稍大的块中,而不是两个单独的块中。

std::make_sharedstd::make_unique 都确保在抛出异常时不会留下任何对象。如果将函数调用为f(std::shared_ptr&lt;int&gt;(new int), std::shared_ptr&lt;int&gt;(new int)),那么编译器可能首先分配两个int 对象,然后构造两个shared_ptr&lt;int&gt; 对象。如果 second 分配失败,并且还没有设置 shared_ptr&lt;int&gt; 对象来释放销毁时的内存,那么您就有内存泄漏。 std::make_sharedstd::make_unique 在一个函数调用中结合int 的分配和std::shared_ptr&lt;int&gt; 的构造,在另一个函数调用中结合int 的另一个分配和std::shared_ptr&lt;int&gt; 的另一个构造。函数调用不能重叠,所以如果第二次分配失败,已经有一个共享指针将被销毁,同样撤销第一次分配。

【讨论】:

  • make_ 智能指针还通过消除未配对的new 来启用“每个new 都与delete 配对”的健全性检查。
  • 不确定 make_XXX 如何保证您最后一段中的内存释放。能不能说的详细点。
  • @LokiAstari 这样更好吗?
  • 是的。抱歉,我只是在逻辑飞跃时遇到了麻烦,即整个函数 make_XX() 在第二次函数调用之前完成。
【解决方案2】:

虽然它可能是主观的,但这种技术的一个主要优点是:

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

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

但应该注意的是,这不是关于“保存几个字符”,而是关于使您的代码更通用,并避免在函数调用中被绑定到具体类型。

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

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

  2. 使用std::make_shared 效率更高,因为它一次性分配您的对象以及shared_ptr 对象,从而降低分配开销并可能更好地对齐缓存。

【讨论】:

    【解决方案3】:

    make_unique 向您隐藏“原始”指针,这通常是一件好事 - 它不易出错。 make_shared 可以改善 shared_ptr&lt;X&gt; 实例的内存分配。通常,当您使用shared_ptr&lt;X&gt; 构造函数时,它会分配内存两次,首先是X 的实例,其次是它的内部数据(例如引用计数器)。 make_shared 启用优化 - 它将创建包含 X 和引用计数器的单个内部结构,因此它将执行单个内存分配。和之前一样,它隐藏了原始指针。

    【讨论】:

    • 但是作为一个缺点,如果你保留一个weak_ptr,你的shared_ptr 中的所有内存都将保持活动状态,而不仅仅是ref_count 块。 (但大多数时候这并不重要)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-20
    • 2022-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-26
    • 2015-06-10
    相关资源
    最近更新 更多