C++11 C+的效率+;11对于已构建的对象,使用std::move与emplace_back()推送_back()

C++11 C+的效率+;11对于已构建的对象,使用std::move与emplace_back()推送_back(),c++11,move-semantics,push-back,emplace,C++11,Move Semantics,Push Back,Emplace,在C++11中,emplace_back()通常比push_back()更受欢迎(在效率方面),因为它允许就地构造,但是在对已构造的对象使用push_back(std::move())时仍然是这样吗? 例如,emplace\u back()在以下情况下仍然首选吗 std::string mystring(“hello world”); std::vector myvector; myvector.emplace_back(mystring); myvector.push_back(std::mo

在C++11中,
emplace_back()
通常比
push_back()
更受欢迎(在效率方面),因为它允许就地构造,但是在对已构造的对象使用
push_back(std::move())
时仍然是这样吗?

例如,
emplace\u back()
在以下情况下仍然首选吗

std::string mystring(“hello world”);
std::vector myvector;
myvector.emplace_back(mystring);
myvector.push_back(std::move(mystring));
//(当然,假设我们不关心使用mystring after的值)
此外,在上述示例中,执行以下操作是否有任何好处:

myvector.emplace_back(std::move(mystring));

或者在这里移动是完全多余的,还是没有效果?

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

  • emplace\u back(mystring)
    :这是新元素的就地构造,包含您提供的任何参数。由于您提供了一个左值,该就地构造实际上是一个副本构造,即,这与调用
    push\u-back(mystring)

  • push_-back(std::move(mystring))
    :这将调用移动插入,在
    std::string
    的情况下,它是一个就地移动构造

  • emplace\u back(std::move(mystring))
    :这也是一个带有您提供的参数的就地构造。因为该参数是一个右值,所以它调用
    std::string
    的move构造函数,也就是说,它是一个如图2所示的就地move构造

  • 换句话说,如果用一个类型为T的参数调用,无论是右值还是左值,
    emplace\u back
    push\u back
    都是等效的

    但是,对于任何其他参数,
    emplace\u back
    赢得比赛,例如,在
    向量中使用
    char const*

  • emplace\u back(“foo”)
    调用
    std::string(char const*)
    进行就地构造

  • push_back(“foo”)
    首先必须调用
    std::string(char const*)
    进行匹配函数签名所需的隐式转换,然后像案例2那样进行移动插入。在上面因此,它相当于
    push_back(字符串(“foo”))


  • emplace_back获取一个右值引用列表,并尝试直接就地构造容器元素。您可以使用容器元素构造函数支持的所有类型调用emplace_。 当为非右值引用的参数调用emplace_时,它会“退回”到正常引用,并且当参数和容器元素属于同一类型时,至少会调用复制构造函数ist。 在您的例子中,“myvector.emplace_back(mystring)”应该复制字符串,因为编译器无法知道参数myvector是可移动的。因此,插入std::move,以获得所需的好处。
    对于已经构建的元素,push-back应该和emplace-back一样有效。

    myvector.emplace-back(mystring)复制并且不移动。其他两个移动和应该是等效的。另请参见此问题和结果:这是一种描述转发/通用引用的有趣方式。移动构造函数通常比复制构造函数更有效,因此使用右值(案例2,3)比使用左值(案例1)更有效尽管语义相同,但这种情况如何?void foo(string&&s){vector.emplace(s);//1 vector.emplace(std::move(s));//2}@VALOD这些都是我列表中的数字1和3
    s
    可以定义为仅绑定到右值的右值引用,但在
    foo
    内部,
    s
    是左值。