C++11中使用std::move的push_back()与emplace_back()对于已构造对象的效率比较。

110
在C++11中,emplace_back()通常比push_back()更受欢迎(就效率而言),因为它允许原地构造。但是,当使用已经构造的对象时,如果使用push_back(std::move()),是否仍然如此? 例如,在以下情况下,emplace_back()是否仍然优先考虑?
std::string mystring("hello world");
std::vector<std::string> myvector;

myvector.emplace_back(mystring);
myvector.push_back(std::move(mystring));
// (of course assuming we don't care about using the value of mystring after)

此外,在上面的例子中,采用以下方式有什么好处吗:
myvector.emplace_back(std::move(mystring));

这个操作是否完全多余,或者没有任何影响?

myvector.emplace_back(mystring); 复制而不移动。另外两个是移动操作,应该是等价的。 - T.C.
请参阅以下问题和结果:有关插入(insert)和就地构造(emplace)的 VC++ 调查 - ildjarn
2个回答

141
让我们看一下你提供的不同调用的作用:
  1. emplace_back(mystring):这是使用提供的任何参数进行新元素就地构造。由于您提供了一个左值,因此该就地构造实际上是复制构造,即这相当于调用push_back(mystring)

  2. push_back(std::move(mystring)):这将调用移动插入,在std::string的情况下是就地移动构造。

  3. emplace_back(std::move(mystring)):这再次是使用提供的参数进行就地构造。由于该参数是右值,因此它调用std::string的移动构造函数,即它是类似于2中的就地移动构造。

换句话说,如果使用类型为T的一个参数调用,无论是rvalue还是lvalue,emplace_backpush_back是等效的。

但是,对于任何其他参数,emplace_back胜出比赛,例如在vector<string>中使用char const*

  1. emplace_back("foo")调用std::string(char const*)进行就地构造。

  2. push_back("foo")首先必须调用std::string(char const*)进行隐式转换以匹配函数的签名,然后类似于2中的移动插入。因此它等同于push_back(string("foo"))


1
移动构造函数通常比复制构造函数更高效,因此使用右值(情况2、3)比使用左值(情况1)更高效,尽管语义相同。 - Ryan Li
这种情况怎么办?void foo(string&& s) { vector.emplace(s); // 1 vector.emplace(std::move(s)); // 2 } - VALOD9
@VALOD 这些是我的列表中的数字1和3。 s 可以被定义为只绑定到 rvalue 的 rvalue 引用,但在 foo 中,s 是一个 lvalue。 - Arne Mertz
我相信你所说的“move-insertion”是指为了提高效率而特殊实现的(constexpr) void push_back( T&& value );:https://en.cppreference.com/w/cpp/container/vector/push_back。不过,我在那个名字下找不到任何相关内容。 - Zack Light

2

emplace_back接受一个右值引用列表,并尝试直接构造一个容器元素。您可以使用容器元素构造函数支持的所有类型来调用emplace_back。 当为不是右值引用的参数调用emplace_back时,它会“回退”到普通引用,并且当参数和容器元素是相同类型时,至少会调用复制构造函数。 在您的情况下,“myvector.emplace_back(mystring)”应该复制字符串,因为编译器无法知道参数myvector是否可移动。因此,请插入std :: move以获得所需的好处。 对于已经构造的元素,push_back应该与emplace_back一样有效。


3
这是一种有趣的描述转发/通用引用的方式。 - T.C.

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