Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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?

like image 890
Zebrafish Avatar asked Feb 18 '18 09:02

Zebrafish


1 Answers

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.

like image 87
WhiZTiM Avatar answered Oct 10 '22 06:10

WhiZTiM