首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >push_back vs emplace_back

push_back vs emplace_back
EN

Stack Overflow用户
提问于 2010-11-29 20:04:09
回答 7查看 466.1K关注 0票数 961

我对push_backemplace_back之间的区别感到有点困惑。

代码语言:javascript
复制
void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);

由于有一个采用右值引用的push_back重载,我不太明白emplace_back的用途是什么?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2010-11-30 02:00:29

除了访问者所说的:

MSCV10提供的函数void emplace_back(Type&& _Val)是不一致和冗余的,因为正如您所提到的,它严格等同于push_back(Type&& _Val)

但是emplace_back真正的C++0x形式是非常有用的:void emplace_back(Args&&...)

它没有接受value_type,而是接受一个可变的参数列表,所以这意味着你现在可以完美地转发参数,并直接将对象构造到容器中,而根本不需要临时参数。

这很有用,因为无论RVO和move语义给表带来了多大的灵活性,仍然存在一些复杂的情况,其中push_back可能会进行不必要的复制(或移动)。例如,使用std::map的传统insert()函数,您必须创建一个临时的,然后将其复制到std::pair<Key, Value>中,然后将其复制到地图中:

代码语言:javascript
复制
std::map<int, Complicated> m;
int anInt = 4;
double aDouble = 5.0;
std::string aString = "C++";

// cross your finger so that the optimizer is really good
m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString))); 

// should be easier for the optimizer
m.emplace(4, anInt, aDouble, aString);

那么为什么他们不在MSVC中实现正确版本的emplace_back呢?实际上,它也困扰了我一段时间,所以我在Visual C++ blog上问了同样的问题。以下是微软Visual C++标准库实现的官方维护者斯蒂芬·T·拉瓦维的回答。

问: beta 2 emplace函数现在只是一种占位符吗?

答:正如你可能知道的,可变模板并没有在VC10中实现。对于make_shared<T>()、元组和<functional>中的新事物,我们使用预处理器机制来模拟它们。这种预处理器机器相对较难使用和维护。此外,它还会显著影响编译速度,因为我们必须反复包含副标题。由于我们的时间限制和编译速度的考虑,我们没有在emplace函数中模拟各种模板。

当可变模板在编译器中实现时,您可以预期我们将在库中利用它们,包括在emplace函数中。我们非常重视一致性,但不幸的是,我们不能一下子做完所有的事情。

这是一个可以理解的决定。每个只尝试过一次用预处理器可怕的技巧来模拟可变模板的人都知道这种东西有多恶心。

票数 687
EN

Stack Overflow用户

发布于 2010-11-29 20:47:57

emplace_back不应该接受vector::value_type类型的参数,而应该接受转发给附加项的构造函数的可变参数。

代码语言:javascript
复制
template <class... Args> void emplace_back(Args&&... args); 

可以传递一个value_type,该the将被转发给复制构造函数。

因为它转发参数,这意味着如果您没有rvalue,这仍然意味着容器将存储“复制的”副本,而不是移动的副本。

代码语言:javascript
复制
 std::vector<std::string> vec;
 vec.emplace_back(std::string("Hello")); // moves
 std::string s;
 vec.emplace_back(s); //copies

但以上内容应该与push_back所做的相同。它可能更适合于像这样的用例:

代码语言:javascript
复制
 std::vector<std::pair<std::string, std::string> > vec;
 vec.emplace_back(std::string("Hello"), std::string("world")); 
 // should end up invoking this constructor:
 //template<class U, class V> pair(U&& x, V&& y);
 //without making any copies of the strings
票数 231
EN

Stack Overflow用户

发布于 2015-10-28 00:42:57

emplace_back的优化可以在下一个示例中演示。

对于emplace_back构造函数,将调用A (int x_arg)。对于push_back,首先调用A (int x_arg),然后调用move A (A &&rhs)

当然,构造函数必须标记为explicit,但对于当前示例,最好去掉显性。

代码语言:javascript
复制
#include <iostream>
#include <vector>
class A
{
public:
  A (int x_arg) : x (x_arg) { std::cout << "A (x_arg)\n"; }
  A () { x = 0; std::cout << "A ()\n"; }
  A (const A &rhs) noexcept { x = rhs.x; std::cout << "A (A &)\n"; }
  A (A &&rhs) noexcept { x = rhs.x; std::cout << "A (A &&)\n"; }

private:
  int x;
};

int main ()
{
  {
    std::vector<A> a;
    std::cout << "call emplace_back:\n";
    a.emplace_back (0);
  }
  {
    std::vector<A> a;
    std::cout << "call push_back:\n";
    a.push_back (1);
  }
  return 0;
}

输出:

代码语言:javascript
复制
call emplace_back:
A (x_arg)

call push_back:
A (x_arg)
A (A &&)
票数 123
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4303513

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档