简体   繁体   English

具有左值表达式的std :: vector :: emplace_back

[英]std::vector::emplace_back with lvalue expression

Does it ever make practical sense to use emplace_back with lvalue of some struct S : emplace_back与某些struct S左值一起使用是否真的有意义:

like this: 像这样:

std::vector<S> v;
auto s = S(/*...*/);
v.emplace_back(s);

Instead of just: 而不仅仅是:

v.emplace_back(/* S constructor arguments */);

or is it just plain misuse of emplace_back , that only happen to work because const S& (and thus a copy constructor) is legitimate instantiation for Args... args inside emplace_back , and it is not forbidden explicitely? 或者它只是简单地滥用emplace_back ,只是因为const S& (以及复制构造函数)是emplace_back Args... args合法实例,并且它不是明确禁止的吗?

As you already said, passing const S& would just invoke the copy constructor. 正如您已经说过的,传递const S&只会调用复制构造函数。

Unless you intend to use s in some way before passing it to emplace_back , it is therefore not necessarily wise. 除非你打算在将它传递给emplace_back之前以某种方式使用s ,否则它不一定是明智的。

However, if the code to create s was, for instance, exceptionally long, it could improve readability to put it and the code for emplace_back on separate lines. 但是,如果创建s的代码特别长,它可以提高将它和emplace_back的代码放在不同行上的可读性。 Compilers are extremely good at optimizing such cases and will probably generate the same code anyways (if the copy constructor is default). 编译器非常擅长优化这种情况,并且可能会生成相同的代码(如果复制构造函数是默认的)。 Basic example: https://godbolt.org/z/D1FClE 基本示例: https//godbolt.org/z/D1FClE

If it improves readability or maintainability do it, otherwise there's no value in it. 如果它提高了可读性或可维护性,那么它就没有价值。

If s is not needed later in the code, then it is a misuse of the emplace_back() function. 如果稍后在代码中不需要s ,那么它是对emplace_back()函数的误用。 This is because you are invoking the copy constructor of the S class instead of passing the arguments to the emplace_back() which will use the correct constructor from S . 这是因为您正在调用S类的复制构造函数,而不是将参数传递给emplace_back() ,后者将使用S的正确构造函数。

Consider the following code: 请考虑以下代码:

#include <iostream>
#include <vector>

struct S
{
    S()          {std::cout<< "     default ctor" <<std::endl;}
    S(int)       {std::cout<< "     user-def ctor" <<std::endl;}
    S(const S &) {std::cout<< "     copy ctor" <<std::endl;}
    S(S &&)      {std::cout<< "     move ctor" <<std::endl;}
};

int main()
{
    std::vector<S> v;
    v.reserve(5);

    std::cout<< "auto calls: " <<std::endl;
    auto s = S();
    std::cout<<std::endl;

    std::cout<< "emplace_back( s ) calls: " <<std::endl;
    v.emplace_back(s);
    std::cout<<std::endl;

    std::cout<< "emplace_back( std::move(s) ) calls: " <<std::endl;
    v.emplace_back(std::move(s));
    std::cout<<std::endl;

    std::cout<< "emplace_back( S{} ) calls: " <<std::endl;
    v.emplace_back(S{});
    std::cout<<std::endl;

    std::cout<< "emplace_back( ) calls: " <<std::endl;
    v.emplace_back();
    std::cout<<std::endl;

    std::cout<< "emplace_back( 2 ) calls: " <<std::endl;
    v.emplace_back(2);
    std::cout<<std::endl;
}

The results are: 结果是:

auto calls: 
     default ctor

emplace_back( s ) calls: 
     copy ctor

emplace_back( std::move(s) ) calls: 
     move ctor

emplace_back( S{} ) calls: 
     default ctor
     move ctor

emplace_back( ) calls: 
     default ctor

emplace_back( 2 ) calls: 
     user-def ctor

The reserve is used to allocate space for 5 S s. 储备用于为5分配空间S秒。 Without reserving the space, the outputs would include additional calls to the copy ctors from the vector. 如果不保留空间,输出将包括从向量中复制ctors的附加调用。

When you just pass the arguments to the constructor of S (in this case, nothing), the emplace_back() creates an S object using the default ctor directly inside the vector. 当你只是将参数传递给S的构造函数(在这种情况下,没有)时, emplace_back()使用直接在向量内部的默认ctor创建一个S对象。

Btw, see the example in godbolt which is your friend in these cases to see exactly what happens in the background. 顺便说一下,看看godbolt中的例子,在这些情况下,你的朋友可以看到背景中发生了什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM