JamesNZ
JamesNZ

Reputation: 187

Odd std::vector::emplace() compilation error

I've come across a strange compiler error while using std::vector::emplace() and std::vector::emplace_back():

#include <vector>

struct Foo {
    int bar;

    Foo(int _bar) : bar(_bar) { }
};

int main() {
    // Declaration 1
    std::vector<Foo> vec(10);

    // Declaration 2
    // std::vector<Foo> vec{};

    vec.emplace_back(1);

    return 0;
}

When I compile this, I get the following error:

In file included from /usr/include/c++/6/vector:62:0,
                 from prog.cpp:2:
/usr/include/c++/6/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = Foo; _Args = {}]’:
/usr/include/c++/6/bits/stl_uninitialized.h:519:18:   required from ‘static _ForwardIterator std::__uninitialized_default_n_1<_TrivialValueType>::__uninit_default_n(_ForwardIterator, _Size) [with _ForwardIterator = Foo*; _Size = long unsigned int; bool _TrivialValueType = false]’
/usr/include/c++/6/bits/stl_uninitialized.h:575:20:   required from ‘_ForwardIterator std::__uninitialized_default_n(_ForwardIterator, _Size) [with _ForwardIterator = Foo*; _Size = long unsigned int]’
/usr/include/c++/6/bits/stl_uninitialized.h:637:44:   required from ‘_ForwardIterator std::__uninitialized_default_n_a(_ForwardIterator, _Size, std::allocator<_Tp>&) [with _ForwardIterator = Foo*; _Size = long unsigned int; _Tp = Foo]’
/usr/include/c++/6/bits/stl_vector.h:1309:36:   required from ‘void std::vector<_Tp, _Alloc>::_M_default_initialize(std::vector<_Tp, _Alloc>::size_type) [with _Tp = Foo; _Alloc = std::allocator<Foo>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/usr/include/c++/6/bits/stl_vector.h:281:30:   required from ‘std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const allocator_type&) [with _Tp = Foo; _Alloc = std::allocator<Foo>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<Foo>]’
prog.cpp:11:25:   required from here
/usr/include/c++/6/bits/stl_construct.h:75:7: error: no matching function for call to ‘Foo::Foo()’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cpp:7:2: note: candidate: Foo::Foo(int)
  Foo(int _bar) : bar(_bar) { }
  ^~~
prog.cpp:7:2: note:   candidate expects 1 argument, 0 provided
prog.cpp:4:8: note: candidate: constexpr Foo::Foo(const Foo&)
 struct Foo {
        ^~~
prog.cpp:4:8: note:   candidate expects 1 argument, 0 provided
prog.cpp:4:8: note: candidate: constexpr Foo::Foo(Foo&&)
prog.cpp:4:8: note:   candidate expects 1 argument, 0 provided

However, if I comment out declaration 1 and use declaration 2 instead, the code compiles fine. What's going on here?

Upvotes: 2

Views: 1034

Answers (2)

NathanOliver
NathanOliver

Reputation: 180965

Your problem is not with vec.emplace_back(1);. Your getting the compilation error because of std::vector<Foo> vec(10);. That line is trying to create a vector with 10 default constructed elements. Since your class does not have a default constructor you cannot create the 10 default elements.

To get it to work you need to provide a instance of the class it can copy into the vector. That would look like

std::vector<Foo> vec(10, Foo(whatever_number_you_want));

Or you could just add a default constructor.


std::vector<Foo> vec{}; does not give you any issues because it does not try to default construct any elements. The empty constructor returns a vector of size 0 meaning no objects were constructed thus avoiding your not defined default constructor.

Upvotes: 6

Stephan Lechner
Stephan Lechner

Reputation: 35154

The reason is that std::vector<Foo> vec(10) will instantiate a vector with 10 "empty" Foo-objects, i.e. instances of class Foo for which the default constructor needs to be called. Your class Foo, however, does not provide a default constructor.

The second statement std::vector<Foo> vec{} instantiates an empty vector, so no Foo-object is instantiated (which would have required a default constructor).

To solve your problem, define a default constructor in Foo:

struct Foo {
    int bar;

    Foo() : bar(0) {};
    Foo(int _bar) : bar(_bar) { };
};

Upvotes: 2

Related Questions