具有已构建对象的std :: move与emplace_back()的C ++ 11 push_back()效率


85

在C ++ 11emplace_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);复制并且不会移动。其他两个动作应相等。
TC

另请参
见此

Answers:


115

让我们看看您提供的不同调用的作用:

  1. emplace_back(mystring):这是新元素的就地构造,带有您提供的任何参数。由于您提供了一个左值,因此就地构造实际上是一个复制构造,即,这与调用相同push_back(mystring)

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

  3. emplace_back(std::move(mystring)):这也是使用您提供的参数的就地构造。由于该参数是一个右值,因此调用的move-constructor std::string,即像2中一样是就地移动-construction。

换句话说,如果使用类型T的一个参数调用,则它是右值或左值,emplace_back并且push_back是等效的。

但是,对于任何其他参数,都可以emplace_back赢得比赛,例如在achar const*中使用a vector<string>

  1. emplace_back("foo")要求string::string(char const*)就地建设。

  2. push_back("foo")首先必须调用string::string(char const*)与函数签名匹配所需的隐式转换,然后再进行如上情况2的移动插入。因此,它等同于push_back(string("foo"))


1
Move构造函数通常比复制构造函数更有效,因此尽管语义相同,但使用rvalue(情况2、3)比使用lvalue(情况1)更有效。
瑞安·李

这样的情况呢?无效foo(string && s){vector.emplace(s); // 1个vector.emplace(std :: move(s)); // 2}
VALOD9

@VALOD这些又是我列表的第1和第3位。s可以被定义为右值引用结合仅右值,但内foos是一个左值。
Arne Mertz

1

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


2
这是描述转发/通用引用的一种有趣方式。
TC
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.