在 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));
或者这里的举动完全是多余的,或者没有效果?
让我们看看您提供的不同调用的作用:
emplace_back(mystring)
:这是新元素的就地构造,无论您提供什么参数。由于您提供了左值,因此就地构造实际上是复制构造,即这与调用 push_back(mystring)
相同
push_back(std::move(mystring))
:这称为移动插入,在 std::string
的情况下是就地移动构造。
emplace_back(std::move(mystring))
:这又是一个包含您提供的参数的就地构造。由于该参数是一个右值,因此它调用 std::string
的移动构造函数,即它是一个像 2 中那样的就地移动构造函数。
换句话说,如果使用一个 T 类型的参数调用,无论是右值还是左值,
emplace_back
和 push_back
是等价的。
但是,对于任何其他参数,
emplace_back
会赢得比赛,例如 char const*
中包含 vector<string>
:
emplace_back("foo")
调用 std::string(char const*)
进行就地构建。
push_back("foo")
首先必须调用 std::string(char const*)
进行匹配函数签名所需的隐式转换,然后像上面的情况 2 那样进行移动插入。因此它相当于 push_back(string("foo"))
emplace_back 获取右值引用列表并尝试直接就地构造容器元素。您可以使用容器元素构造函数支持的所有类型调用 emplace_back。 当对不是右值引用的参数调用 emplace_back 时,它会“回退”到普通引用,并且当参数和容器元素具有相同类型时,至少会调用复制构造函数。 在您的情况下,“myvector.emplace_back(mystring)”应该复制字符串,因为编译器无法知道参数 mystring 是可移动的。因此,使用 std::move 可以给您带来所需的好处。 对于已经构造的元素,push_back 应该和 emplace_back 一样工作。