在新运算符上使用std :: make_unique的优点

nit*_*ing 95 c++ unique-ptr c++14

什么是使用的优势,std::make_uniquenew运营商的初始化std::unique_ptr

换句话说,为什么

std::unique_ptr<SomeObject> a = std::make_unique(SomeObject(...))
Run Code Online (Sandbox Code Playgroud)

比做好

std::unique_ptr<SomeObject> a = new SomeObject(...)
Run Code Online (Sandbox Code Playgroud)

我尝试在线查看很多,我知道new在现代C++中避免使用操作符是一个很好的经验法则,但我不确定在这个确切的场景中有什么优势.它是否可以防止可能发生的任何类型的内存泄漏?做一个std::make_unique比使用更快new吗?

101*_*010 96

好处

  • make_unique教导用户"永远不会说new/ deletenew[]/ delete[]"没有免责声明.

  • make_unique分享两个优点make_shared(排除第三个优势,提高效率).首先,unique_ptr<LongTypeName> up(new LongTypeName(args))必须提LongTypeName两次,同时auto up = make_unique<LongTypeName>(args)提到一次.

  • make_unique防止了由像表达式触发的未指定的评价顺序泄漏foo(unique_ptr<X>(new X), unique_ptr<Y>(new Y)).(遵循"永不言败new" 的建议比"永不言败"更简单new,除非你立即将其命名为unique_ptr".")

  • make_unique为了异常安全而精心实施,建议直接调用unique_ptr构造函数.

什么时候不用 make_unique

  • make_unique如果您需要自定义删除器或从其他地方采用原始指针,请不要使用.

来源

  1. 提案std::make_unique.
  2. Herb Sutter的想法#89解决方案:智能指针

  • _未指定的评估顺序泄漏_问题[已解决](/sf/ask/3770936571/),因为它是从 C++17 开始指定的。 (2认同)

Whi*_*TiM 43

不同之处在于std::make_unique返回一个类型的对象std::unique_ptrnew返回一个指向所创建对象的指针.对于内存分配失败,它们都会抛出.坚持下去,并不是那么简单.进一步阅读.

考虑以下这样的功能:

void func(ClassA* a, ClassB* b){
     ......
}
Run Code Online (Sandbox Code Playgroud)

当你拨打电话时func(new A(), new B()); 编译器可以选择从左到右,或者按照任何顺序评估函数参数.让我们假设从左到右评估:当第一个new表达式成功但第二个new表达式抛出时会发生什么?

这里真正的危险是你遇到这样的例外; 是的,您可能已经捕获了异常new B(),并恢复正常执行,但new A()已经成功,并且其内存将被默默泄露.没有人清理它......*抽泣 ......

但是make_unique,你不能有泄漏,因为堆栈展开会发生(并且先前创建的对象的析构函数将运行).因此,优先考虑make_unique将限制您的异常安全.在这种情况下,std::make_unique提供一个" 基本异常安全 ",分配的内存和创建的对象new无论如何都不会成为孤立的.即使到时间结束...... :-)

你应该阅读Herb Sutter GoTW102

  • @ Nik-Lz`func(new A(),new B())`不会产生`unique_ptr`,答案是关于不使用它会发生什么... (2认同)
  • 清楚地解释由于使用 new 时异常处理不当而产生的问题的要点。第一个答案暗示了异常安全的理由,但没有说清楚。new 和 make_unique 都会抛出异常,但只有 make_unique 会在销毁时处理释放内存。 (2认同)