对于已构造的对象,使用 std::move 的 C++11 Push_back() 与 emplace_back() 的效率

问题描述 投票:0回答:2

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

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

c++11 move-semantics push-back emplace
2个回答
139
投票

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

  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 类型的参数调用,无论是右值还是左值,

emplace_back
push_back
是等价的。

但是,对于任何其他参数,

emplace_back
会赢得比赛,例如
char const*
中包含
vector<string>

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

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


2
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.