C++ 使用 std::make_unique 优于 new 运算符的优点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37514509/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Advantages of using std::make_unique over new operator
提问by niting
What are the advantages of using std::make_unique
over the new
operator for initializing a std::unique_ptr
?
什么是使用的优势,std::make_unique
在new
运营商的初始化std::unique_ptr
?
In other words, why is
换句话说,为什么
std::unique_ptr<SomeObject> a = std::make_unique(SomeObject(...))
better than doing
比做更好
std::unique_ptr<SomeObject> a = new SomeObject(...)
I tried looking up a lot online and I do know that it is a good rule of thumb to avoid the operator new
in modern C++, but I am not sure what the advantages are in this exact scenario. Does it prevent any kind of memory leaks that might happen? Is it faster to do a std::make_unique
than to use new
?
我尝试在网上查了很多资料,我知道new
在现代 C++ 中避免使用运算符是一个很好的经验法则,但我不确定在这种情况下有什么优势。它是否可以防止可能发生的任何类型的内存泄漏?做 astd::make_unique
比使用快new
吗?
采纳答案by 101010
Advantages
好处
make_unique
teaches users "never saynew
/delete
andnew[]
/delete[]
" without disclaimers.make_unique
shares two advantages withmake_shared
(excluding the third advantage, increased efficiency). First,unique_ptr<LongTypeName> up(new LongTypeName(args))
must mentionLongTypeName
twice, whileauto up = make_unique<LongTypeName>(args)
mentions it once.make_unique
prevents the unspecified-evaluation-order leak triggered by expressions likefoo(unique_ptr<X>(new X)
,unique_ptr<Y>(new Y))
. (Following the advice "never saynew
" is simpler than "never saynew
, unless you immediately give it to a namedunique_ptr
".)make_unique
is carefully implemented for exception safety and is recommended over directly callingunique_ptr
constructors.
make_unique
教导用户“永远不要说new
/delete
和new[]
/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
构造函数。
When not to use make_unique
何时不使用 make_unique
- Don't use
make_unique
if you need a custom deleter or are adopting a raw pointer from elsewhere.
make_unique
如果您需要自定义删除器或从其他地方采用原始指针,请不要使用。
Sources
来源
回答by WhiZTiM
The difference is that std::make_unique
returns an object of type std::unique_ptr
and new
returns a pointer to the created object. For memory allocation failures, they will both throw. Hold on, it's not that simple. Read further.
区别在于std::make_unique
返回一个类型的对象std::unique_ptr
并new
返回一个指向创建对象的指针。对于内存分配失败,它们都会抛出。等等,没那么简单。进一步阅读。
Consider such a function below:
考虑下面这样的函数:
void func(ClassA* a, ClassB* b){
......
}
When you make a call like func(new A(), new B())
; The compiler may choose to evaluate the function arguments from left to right, or in any order it so wishes. Let's assume left to right evaluation: What happens when the first new
expression succeeds but the second new
expression throws?
当您拨打类似电话时func(new A(), new B())
;编译器可以选择从左到右计算函数参数,或者按照它希望的任何顺序。让我们假设从左到右计算:当第一个new
表达式成功但第二个new
表达式抛出时会发生什么?
The real danger here is when you catch such exception; Yes, you may have caught the exception thrown by new B()
, and resume normal execution, but new A()
already succeeded, and its memory will be silently leaked. Nobody to clean it up... * sobs...
这里真正的危险是当你捕捉到这样的异常时;是的,你可能已经捕获到 抛出的异常new B()
,并恢复正常执行,但是new A()
已经成功了,它的内存会被悄悄泄漏。没有人来清理它...... *抽泣......
But with make_unique
, you cannot have a leak because, stack unwinding will happen ( and the destructor of the previously created object will run). Hence, having a preference for make_unique
will constrain you towards exception safety. In this case, std::make_unique
provides a "Basic Exception Safety"that the memory allocated and object created by new
will never be orphaned no matter what. Even till the ends of time... :-)
但是使用make_unique
,您不能有泄漏,因为将发生堆栈展开(并且先前创建的对象的析构函数将运行)。因此,偏好make_unique
将限制您使用异常安全。在这种情况下,std::make_unique
提供一个“基本异常安全”,分配的内存和创建的对象new
无论如何都不会孤立。即使直到时间结束... :-)
You should read Herb Sutter GoTW102
你应该阅读Herb Sutter GoTW102