Why does this std::vector::emplace_back fail?

I'm coming across a compiler error that says:

attempting to reference a deleted function

#include <iostream>
#include <vector>

template <typename T>
struct Container
    Container() = default;
    Container(const Container& other) = delete;
    Container(T* ptr) : ptr(ptr) {}
    T* ptr;
    ~Container() { delete ptr; }


struct Foo { Foo(int a, int b) {} };

int main()
    std::vector<Container<Foo>> myvector;
    myvector.push_back(new Foo(1, 2)); // I understand why this doesn't work.
    myvector.emplace_back((new Foo(1, 2))); // I don't understand why this fails


I understand why it says attempting to reference a deleted constructor when I do std::vector::push_back(), because this does a copy and needs to call the copy constructor, which I deleted. But std::vector::emplace_back() is supposed to take the constructor arguments of the type it holds. When I emplace back I give it a pointer to a Foo, and this should be forwarded to the Container::Container(T* ptr) constructor.

What am I missing?

1 answer

  • answered 2018-02-18 09:14 WhiZTiM

    Declaring a User-Defined copy constructor will not define an implicit move constructor; T must either have a copy constructor or a move constructor to push_back or emplace_back* an object into a std::vector<T>.

    From the docs, see the requirements on T to instantiate a std::vector<T>. (No restriction here, read on) ..emphasis mine

    The requirements that are imposed on the elements depend on the actual operations performed on the container. Generally, it is required that element type meets the requirements of Erasable, but many member functions impose stricter requirements. This container (but not its members) can be instantiated with an incomplete element type if the allocator satisfies the allocator completeness requirements.

    From std::vector<...>::push_back:

    Type requirements

    • T must meet the requirements of CopyInsertable in order to use overload (1).
    • T must meet the requirements of MoveInsertable in order to use overload (2).

    From std::vector<...>::emplace_back:

    Type requirements

    • T (the container's element type) must meet the requirements of MoveInsertable and EmplaceConstructible.

    For emplace_back here, your code would fulfill the EmplaceConstructible criteria, however, because reallcations can happen, you must equally fulfill MoveInsertable.