使用std::make_unique的push_back或emplace_back

35
根据这些问题以及这里的回答,我知道使用C++14的std::make_unique比直接使用emplace_back(new X)更可取。
话虽如此,调用这个函数是否更好呢?
my_vector.push_back(std::make_unique<Foo>("constructor", "args"));
或者
my_vector.emplace_back(std::make_unique<Foo>("constructor", "args"));

也就是说,当我添加一个由std::make_unique构造的std::unique_ptr时,我应该使用push_back还是emplace_back呢?

==== 编辑 ====

为什么呢?c: <--(微笑)


4
使用向量元素类型作为实际参数,push_backemplace_back是必然相同的。 - Cheers and hth. - Alf
相关内容:http://htmlpreview.github.io/?https://github.com/HowardHinnant/papers/blob/master/insert_vs_emplace.html - dyp
@Praetorian 不好意思,谢谢。 - NHDaly
如果您在 unique_ptr 上有自定义删除器,那么情况可能会发生变化。 - Yakk - Adam Nevraumont
1
关于@dyp的链接,我在VS2022上运行了该代码,并且在每种情况下insert和emplace是相同的。 - Thomas
2个回答

34
无论是使用push_back还是emplace_back,对于新对象的构建而言没有区别;因为您已经有了一个unique_ptr<Foo> prvalue(调用make_unique的结果),所以在构造要追加到vector中的元素时,两种方法都会调用unique_ptr移动构造函数。
如果您的用例涉及插入后访问新构建的元素,则自C++17起,emplace_back更方便,因为它返回对该元素的引用。所以,不是:
my_vector.push_back(std::make_unique<Foo>("constructor", "args"));
my_vector.back().do_stuff();

你可以写

my_vector.emplace_back(std::make_unique<Foo>("constructor", "args")).do_stuff();

1
是的,同意,这就是我问的原因。 :) - NHDaly
3
实际上,它们是有区别的... emplace_back() 返回添加元素的引用,而 push_back() 返回 void。因此,在需要在添加后使用对象的情况下,emplace_back(std::make_unique<>()) 是有用的。 - j b
2
@JamieBullock,嗯,我在3年前回答这个问题时没有什么区别。更新了答案以包括C++17对返回类型的更改。谢谢。 - Praetorian

1
显然
template<class T, class A, class...Args>
void push_unique( std::vector<std::unique_ptr<T>,A>& v, Args&&...args ) {
  v.push_back( std::make_unique<T>(std::forward<Args>(args)...) );
}

是最佳选择:

push_unique(my_vector,"constructor", "args");

很遗憾,这是前缀表示法:(运算符,容器,参数...) 而不是中缀表示法 (容器 运算符 参数...)。
如果有一种方法可以将其转换为中缀表示法,就像 扩展方法命名运算符 那样,那将会很酷。
因为这将会很棒。

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