In place construction of a pair of nonmovable, non copyable in a std::vector

Assume a following non copyable and non movable struct X with no default constructor and with no single argument constructor:

struct X
{
    X(int x, int y) { }
    X(const X&) = delete;
    X(X&&) = delete;
};

and a vector std::vector<pair<X,X>> v. For inserting into v one could use emplace_back if X was constructible from just one argument, since it effectively calls the constructor of std::pair<X,X>.
We could do something like this:

v.emplace_back(X(42,42),X(69,69));

but in this case a move constructor of X gets called and the latter does not compile. Since this is not possible, we have to make use of the std::piecewise_construct constructor of std::pair and call:

v.emplace_back(std::piecewise_construct, std::forward_as_tuple(42,42), std::forward_as_tuple(69,69));

I would expect this to work properly, but the vector, for some reason, is calling move ctor (or copy, if only move was deleted).

For example changing the container to be std::list, everything works just fine. Adding a < operator to X and creating a std::map<X,X> (which has pairs of X as the nodes) or std::set<std::pair<X,X>> and using emplace instead of emplace_back all seems to work. What is wrong with std::vector?

Full code snippet can be found here.

>Solution :

std::vector is subject to reallocation once the size reach the capacity.
when reallocating the elements into a new memory segment std::vector has to copy/move the values from the old segment and this is made by calling copy/move constructors.

if you don’t need that the elements are sequential in memory you can use std::deque instead, since std::deque doesn’t reallocate the elements internally.

you can’t store non copyable and non moveable objects into std::vectors.


EDIT suggested by @Fran├žois Andrieux

In case you still need for any reason an std::vector you may think to use a vector made using std::unique_ptr<X> as value type using std::vector<std::unique_ptr<X>>.

With this solution you still don’t get a sequential order in memory of your elements, and they are keep in memory till they are still in the vector, so except in case you are forced by any reason to use std::vectors, i think the best match is still the std::deque.

Leave a Reply