将std::vector::emplace_back
和std::move
一起使用有什么好处?或者它只是多余的,因为std::vector::emplace_back
将进行inplace-construction?
澄清案例:
std::vector<std::string> bar;
首先
bar.emplace_back(std::move(std::string("some_string")));
第二
std::string str("some_string");
bar.emplace_back(std::move(str));
第三
bar.emplace_back(std::move("some_string"));
答案 0 :(得分:17)
在第二个版本中,有一个优点。当emplace_back
被使用时,调用std::string
将调用std::move
的移动构造函数,这可以保存在副本上(只要该字符串不存储在SSO缓冲区中)。请注意,在这种情况下,这与push_back
基本相同。
std::move
在第一个版本中是不必要的,因为该字符串已经是一个prvalue。
std::move
无关紧要,因为无法移动字符串文字。
最简单,最有效的方法是:
bar.emplace_back("some_string");
这不需要任何不必要的std::string
构造,因为文字完美地转发给构造函数。
答案 1 :(得分:5)
emplace_back
调用了诸如
new (data+size) T(std::forward<Args>(args)...);
如果args
是基本的 - 非右值引用的std::string
,表达式将编译为
new (data+size) std::string(str); //str is lvalue - calls std::string::string(const string& rhs)
意味着将发生复制构造函数。
但是,如果您在std::move
上使用str
,则代码将编译为
new (data+size) std::string(str); //str is r-value reference, calls std::string::string(string&& rhs)
所以移动语义发生了。这是一个巨大的性能提升
请注意,str
是左值,它有一个名称,因此为了从中创建r值引用,您必须使用std::move
。
vec.emplace_back("some literal");
代码将编译为
new (data+size) std::string("literal"); //calls std::string::string(const char*);
所以没有临时工。
第三个例子是胡说八道。你无法移动文字。
答案 2 :(得分:3)
emplace_back
的整个想法是摆脱复制和移动操作。您只需将std::string
的输入参数传递给emplace_back
即可。将在std::string
方法中构建emplace_back
对象。
bar.emplace_back("some_string");
如果您已有字符串,则使用std::move
是有意义的。通过从std::string
移动数据,将在emplace_back
内构建str
个对象。
std::string str("some_string");
bar.emplace_back(std::move(str));
答案 3 :(得分:1)
在第二种情况下,有一点需要这样做。请考虑以下代码:
int main()
{
std::vector<std::string> bar;
std::string str("some_string");
bar.emplace_back(std::move(str)); str.clear();
// bar.emplace_back(str);
std::cout << str << std::endl;
}
如果您将注释更改为上面的行,您可以看到最终会有两个副本&#34; some_string&#34; (bar
中的一个和str
中的一个)。所以它确实改变了一些东西。
否则,第一个是移动临时,第三个是移动一个常量字符串文字。它什么都不做。