使用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
更快吗?
答案 0 :(得分:82)
make_unique
教会用户&#34;永远不要说new
/ delete
和
new[]
/ delete[]
&#34;没有免责声明。
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))
。 (遵循建议&#34;永远不要说new
&#34;比简单更简单
&#34;永远不要说new
,除非您立即将其提供给名为unique_ptr
&#34;。)
make_unique
是针对异常安全而精心实施的,建议直接调用unique_ptr
构造函数。
make_unique
make_unique
。答案 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