与 new 操作符相比,使用 std: : make _ only 的优点

与使用 new操作符初始化 std::unique_ptr相比,使用 std::make_unique的优点是什么?

换句话说,为什么

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

总比做好

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

我在网上查了很多资料,我知道在现代 C + + 中避免使用操作符 new是一个很好的经验法则,但是我不确定在这种情况下有什么好处。它能防止任何可能发生的内存泄漏吗?做 std::make_unique比使用 new快吗?

155650 次浏览

好处

  • make_unique教导用户“永远不要说 new/deletenew[]/delete[]”无免责声明。

  • 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))这样的表达式触发的泄漏(遵循“永远不要说 new”的建议比 “永远不要说 new,除非你立即把它给一个命名为 unique_ptr。”)

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

何时不使用 make_unique

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

消息来源

  1. std::make_unique的建议。
  2. Herb Sutter 的 GotW # 89解决方案: 智能指针

区别在于,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的偏好将限制您使用 例外安全。在这种情况下,std::make_unique提供了一个 ”< em > 基本例外情况安全 ,无论如何,new分配的内存和创建的对象永远不会孤立。直到时间的尽头... : -)

你应该读 Herb Sutter GoTW102