在新运算符

时间:2016-05-29 20:14:48

标签: c++ c++14 unique-ptr

使用std::make_unique优于new运算符来初始化std::unique_ptr有什么好处?

换句话说,为什么

std::unique_ptr<SomeObject> a = std::make_unique(SomeObject(...))

比做

更好
std::unique_ptr<SomeObject> a = new SomeObject(...)

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

2 个答案:

答案 0 :(得分:82)

优点

  • make_unique教会用户&#34;永远不要说new / deletenew[] / delete[]&#34;没有免责声明。

  • make_uniquemake_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))。 (遵循建议&#34;永远不要说new&#34;比简单更简单 &#34;永远不要说new,除非您立即将其提供给名为unique_ptr&#34;。)

  • make_unique是针对异常安全而精心实施的,建议直接调用unique_ptr构造函数。

何时不使用make_unique

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

来源

  1. Proposal of std::make_unique
  2. Herb Sutter's GotW #89 Solution: Smart Pointers

答案 1 :(得分:35)

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

考虑以下这样的功能:

void func(ClassA* a, ClassB* b){
     ......
}

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

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

但是使用make_unique,您不会有泄漏,因为堆栈展开将发生(并且先前创建的对象的析构函数将运行)。因此,优先选择make_unique会将您限制在exception safety。在这种情况下,std::make_unique提供"Basic Exception Safety",分配的内存和new创建的对象无论如何都不会成为孤儿。直到时间结束......: - )

您应该阅读Herb Sutter GoTW102