简体   繁体   中英

Does gcc have a extension overload for std::vector::emplace_back?

According tocppreference , std::vector::emplace_back has only one signature, which is:

template< class... Args >
reference emplace_back( Args&&... args );

And in the description, it says emplace_back is supposed to forward each of its arguments to the constructor of the type in the vector . However, when I tested the following code using gcc 12.2, it successfully compiles:

#include <iostream>
#include <vector>

class Foo
{
public:
    int x;
    int y;
    Foo(int x, int y) : x(x), y(y)
    {}
};

int main()
{
    std::vector<Foo> foos;
    Foo foo(1, 2);
    foos.push_back(std::move(foo));
    foos.emplace_back(foo); // weird
}

(See on compiler explorer )

I expected the line foos.emplace_back(foo); to fail the compilation. It seems as if emplace_back has this overload:

template< class T >
reference emplace_back( T& arg );

which isn't mentioned in the documentation. Am I missing something or is this just a compiler extension?

 foos.emplace_back(foo); // weird

That's weird indeed! You ask to emplace_back , meaning you're calling the constructor, and you're passing foo to the constructor. Hence, you're calling the copy constructor. push_back would have done the same!

That's an implicitly defined default copy constructor, see cppreference on Copy Constructors :

If no user-defined copy constructors are provided for a class type (struct, class, or union), the compiler will always declare a copy constructor as a non-explicit inline public member of its class.

You didn't define a copy constructor, so the compiler did that for you, as dictated by C++. You can avoid that and make your compilation fail:

class Foo
{
public:
    int x;
    int y;
    Foo(int x, int y) : x(x), y(y)
    {}
    
    //! Explicitly deleted default copy constructor.
    Foo(const Foo&) = delete;
};
 foos.push_back(std::move(foo));

He're you're calling the move constructor. Note that you're using foo after moving from it, that's more or less illegal (you throwing std::move at foo means that foo is no longer supposed to hold any resources.)

Should you really happen to just want to delete the move constructor, same syntax, basically: Foo(Foo&&) = delete; .

template< class... Args >
reference emplace_back( Args&&... args );

can deduced to something like (with Args = Foo& )

reference emplace_back( Foo& && args[0] );

which collapse to

reference emplace_back( Foo& args[0] );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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