C++ push_back 与 emplace_back

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4303513/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:04:31  来源:igfitidea点击:

push_back vs emplace_back

c++visual-studio-2010stlc++11move-semantics

提问by ronag

I'm a bit confused regarding the difference between push_backand emplace_back.

我对push_back和之间的区别有点困惑emplace_back

void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);

As there is a push_backoverload taking a rvalue reference I don't quite see what the purpose of emplace_backbecomes?

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

采纳答案by Thomas Petit

In addition to what visitor said :

除了访客所说的:

The function void emplace_back(Type&& _Val)provided by MSCV10 is non conforming and redundant, because as you noted it is strictly equivalent to push_back(Type&& _Val).

void emplace_back(Type&& _Val)MSCV10 提供的功能不符合标准和冗余,因为正如您所指出的,它严格等同于push_back(Type&& _Val).

But the real C++0x form of emplace_backis really useful: void emplace_back(Args&&...);

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

Instead of taking a value_typeit takes a variadic list of arguments, so that means that you can now perfectly forward the arguments and construct directly an object into a container without a temporary at all.

而不是采取一个value_type它需要的参数的可变参数列表,这样就意味着,你现在可以完美地提出的论据和结构直接对象放入容器,但未一个临时的。

That's useful because no matter how much cleverness RVO and move semantic bring to the table there is still complicated cases where a push_back is likely to make unnecessary copies (or move). For example, with the traditional insert()function of a std::map, you have to create a temporary, which will then be copied into a std::pair<Key, Value>, which will then be copied into the map :

这很有用,因为无论 RVO 和移动语义有多么聪明,仍然存在一些复杂的情况,其中 push_back 可能会进行不必要的复制(或移动)。例如,使用 a 的传统insert()功能std::map,您必须创建一个临时文件,然后将其复制到 a 中std::pair<Key, Value>,然后将其复制到 map 中:

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);

So why didn't they implement the right version of emplace_back in MSVC? Actually, it bugged me too a while ago, so I asked the same question on the Visual C++ blog. Here is the answer from Stephan T Lavavej, the official maintainer of the Visual C++ standard library implementation at Microsoft.

那么为什么他们没有在 MSVC 中实现正确版本的 emplace_back 呢?实际上,不久前它也困扰了我,所以我在Visual C++ 博客上问了同样的问题。这是微软 Visual C++ 标准库实现的官方维护者 Stephan T Lavavej 的回答。

Q: Are beta 2 emplace functions just some kind of placeholder right now?

A: As you may know, variadic templates aren't implemented in VC10. We simulate them with preprocessor machinery for things like make_shared<T>(), tuple, and the new things in <functional>. This preprocessor machinery is relatively difficult to use and maintain. Also, it significantly affects compilation speed, as we have to repeatedly include subheaders. Due to a combination of our time constraints and compilation speed concerns, we haven't simulated variadic templates in our emplace functions.

When variadic templates are implemented in the compiler, you can expect that we'll take advantage of them in the libraries, including in our emplace functions. We take conformance very seriously, but unfortunately, we can't do everything all at once.

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

答:您可能知道,VC10 中没有实现可变参数模板。我们使用预处理器机制模拟它们,例如 make_shared<T>()、元组和<functional>. 这种预处理机器相对难以使用和维护。此外,它会显着影响编译速度,因为我们必须反复包含子标题。由于我们的时间限制和编译速度问题,我们没有在 emplace 函数中模拟可变参数模板。

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

It's an understandable decision. Everyone who tried just once to emulate variadic template with preprocessor horrible tricks knows how disgusting this stuff gets.

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

回答by visitor

emplace_backshouldn't take an argument of type vector::value_type, but instead variadic arguments that are forwarded to the constructor of the appended item.

emplace_back不应采用 type 的参数vector::value_type,而应采用传递给附加项的构造函数的可变参数参数。

template <class... Args> void emplace_back(Args&&... args); 

It is possible to pass a value_typewhich will be forwarded to the copy constructor.

可以传递value_type将转发给复制构造函数的 a 。

Because it forwards the arguments, this means that if you don't have rvalue, this still means that the container will store a "copied" copy, not a moved copy.

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

 std::vector<std::string> vec;
 vec.emplace_back(std::string("Hello")); // moves
 std::string s;
 vec.emplace_back(s); //copies

But the above should be identical to what push_backdoes. It is probably rather meant for use cases like:

但是上面的应该是相同的push_back。它可能更适用于以下用例:

 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

回答by vadikrobot

Optimization for emplace_backcan be demonstrated in next example.

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

For emplace_backconstructor A (int x_arg)will be called. And for push_backA (int x_arg)is called first and move A (A &&rhs)is called afterwards.

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

Of course, the constructor has to be marked as explicit, but for current example is good to remove explicitness.

当然,构造函数必须标记为explicit,但对于当前示例来说,最好删除显式。

#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;
}

output:

输出:

call emplace_back:
A (x_arg)

call push_back:
A (x_arg)
A (A &&)

回答by Dharma

A nice code for the push_back and emplace_back is shown here.

此处显示了 push_back 和 emplace_back 的一个很好的代码。

http://en.cppreference.com/w/cpp/container/vector/emplace_back

http://en.cppreference.com/w/cpp/container/vector/emplace_back

You can see the move operation on push_back and not on emplace_back.

您可以在 push_back 而非 emplace_back 上看到移动操作。

回答by Dharma

One more in case of lists:

在列表的情况下还有一个:

// constructs the elements in place.                                                
emplace_back("element");


//It will create new object and then copy(or move) its value of arguments.
push_back(explicitDataType{"element"});

回答by Germán Diago

emplace_backconforming implementation will forward arguments to the vector<Object>::value_typeconstructor when added to the vector. I recall Visual Studio didn't support variadic templates, but with variadic templates will be supported in Visual Studio 2013 RC, so I guess a conforming signature will be added.

emplace_backvector<Object>::value_type当添加到向量时,符合的实现会将参数转发给构造函数。我记得 Visual Studio 不支持可变参数模板,但是 Visual Studio 2013 RC 将支持可变参数模板,所以我想会添加一个符合要求的签名。

With emplace_back, if you forward the arguments directly to vector<Object>::value_typeconstructor, you don't need a type to be movable or copyable for emplace_backfunction, strictly speaking. In the vector<NonCopyableNonMovableObject>case, this is not useful, since vector<Object>::value_typeneeds a copyable or movable type to grow.

使用emplace_back,如果您将参数直接转发给vector<Object>::value_type构造emplace_back函数,则严格来说,您不需要可移动或可复制的函数类型。在这种vector<NonCopyableNonMovableObject>情况下,这没有用,因为vector<Object>::value_type需要可复制或可移动的类型才能增长。

But notethat this could be useful for std::map<Key, NonCopyableNonMovableObject>, since once you allocate an entry in the map, it doesn't need to be moved or copied ever anymore, unlike with vector, meaning that you can use std::mapeffectively with a mapped type that is neither copyable nor movable.

请注意,这可能对 有用std::map<Key, NonCopyableNonMovableObject>,因为一旦您在映射中分配了一个条目,就不再需要移动或复制它vector,这与 with 不同,这意味着您可以std::map有效地使用既不可复制也不可复制的映射类型活动。

回答by vaibhav kumar

Specific use case for emplace_back: If you need to create a temporary object which will then be pushed into a container, use emplace_backinstead of push_back. It will create the object in-place within the container.

特定用例emplace_back:如果您需要创建一个临时对象,然后将其推送到容器中,请使用emplace_back代替push_back。它将在容器内就地创建对象。

Notes:

笔记:

  1. push_backin the above case will create a temporary object and move it into the container. However, in-place construction used for emplace_backwould be more performant than constructing and then moving the object (which generally involves some copying).
  2. In general, you can use emplace_backinstead of push_backin all the cases without much issue. (See exceptions)
  1. push_back在上述情况下将创建一个临时对象并将其移动到容器中。但是,用于 的就地构造emplace_back比构造然后移动对象(通常涉及一些复制)的性能更高。
  2. 通常,您可以在所有情况下使用emplace_back而不是push_back没有太大问题。(见例外