为什么要使用make_unique函数来初始化unique_ptr?

6

来源:http://herbsutter.com/2013/05/22/gotw-5-solution-overriding-virtual-functions/

为什么我们应该这样写:

auto pb = unique_ptr<base>{ make_unique<derived>() };

不要只是:

auto pb = make_unique<derived>();

我的唯一猜测是,如果我们想要使用auto,我们需要帮助它推断正确的类型(这里是base)。

如果是这样,那么对我来说,这将是非常怀疑的优点..输入auto,然后在=右侧输入大量初始化..

我错过了什么吗?


1
嗯,为什么?因为你想要第一件事而不是第二件事吗?它们并不等价。(检查decltype(pb) - R. Martinho Fernandes
1
这里有一件事很明显,如果你有一个 derived 的 smart_pointer,你不能轻易地将它转换为 base。因为与 base *x; 和 derived *y; 不同的是,在类型层次结构中没有关系。 - Alexander Oh
4
想知道,unique_ptr<base> pb = make_unique<derived>(); 是否更简洁?自动类型推断存在并不意味着我们必须使用它。 - FredericS
@FredericS:这样会稍微更短一些,对于不习惯C++11的人来说更加熟悉,而且更少显式地涉及到隐式转换。这是否使其更“简单”是审美判断的问题。 - Mike Seymour
我仍然喜欢使用auto pb = unique_ptr<base>(new derived());来保持清晰明了。 - Sander De Dycker
1
@SanderDeDycker 用统一初始化更好:{} - emesx
3个回答

10

问题在于第一种选项将pb变成了一个unique_ptr<base>,而第二种选项将pb变成了一个unique_ptr<derived>。在您的情况下,两者是否都正确取决于您对pb该做什么-但是两者绝不等效。

如果您的程序中涉及到需要使用unique_ptr<base>的部分(也许因为稍后要让它指向不同的派生类的实例),那么第二种解决方案就根本行不通。

例如:

auto pb = unique_ptr<base>{ make_unique<derived>() };
// ...
pb = make_unique<derived2>(); // This is OK
// ...

鉴于:

auto pb = make_unique<derived>();
// ...
pb = make_unique<derived2>(); // ERROR! "derived2" does not derive from "derived"
// ...

@AndyProwl 隐藏证据,是吗? - Bartek Banachewicz
@BartekBanachewicz: 我?我从来不会这样做的!(...删除您的评论需要多少费用?);) - Andy Prowl
5
C++现在很丑陋。我想要我的new/delete回来! - Lightness Races in Orbit
@BoundaryImposition 没有人拿走了它们。现在你只是有其他的选择而已。 - tambre

6
我的猜测是,如果我们想要自动,我们需要帮助它推断正确的类型(这里是基类)。 没错。没有转换,pb将是指向derived的指针,这可能不是您想要的。例如,您无法将其重新分配为拥有base或其他派生类对象。
如果是这样,那么对我来说,这将是非常值得怀疑的优点。
我倾向于同意。作者在comment中指出,他这样做是因为他喜欢尽可能多地使用类型推断,并在必要时使用显式转换。时间会告诉我们这种风格是否变得普遍。

+1 对于Herb的评论链接(以及您的好回答:) - emesx

4
auto pb = unique_ptr<base>{ make_unique<derived>() };

上述代码创建了一个包含derivedunique_ptr<base>
auto pb = make_unique<derived>();

上面的代码创建了一个包含派生类的unique_ptr<derived>。
尽管用第一个代码替换第二个代码也可以,但它们实际上是不同的。
顺便说一句,在链接的文章中搜索make_unique会有人回答这个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接