std :: vector :: emplace_back和std :: move

时间:2016-02-15 08:51:59

标签: c++ c++11 vector move-semantics

std::vector::emplace_backstd::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"));

4 个答案:

答案 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中的一个)。所以它确实改变了一些东西。

否则,第一个是移动临时,第三个是移动一个常量字符串文字。它什么都不做。