Pergunta

According to N3485 §23.3.2.2:

(...) the implicit move constructor and move assignment operator for array require that T be MoveConstructible or MoveAssignable, respectively.

So, std::array supports move semantics if the type of its elements does. Great!

However, what does this really mean? I tend to picture this type as a safer version of an array providing an STL-compliant interface but, if this is true, then how can an std::array move-construct its elements? Can I do the same with an ordinary array?

Foi útil?

Solução

However, what does this really mean?

It means that, if the element type is movable, then so is the array type.

std::array<movable, 42> move_from = {...};
std::array<movable, 42> move_to = std::move(move_from); // moves all the elements

I tend to picture this type as a safer version of an array providing an STL-compliant interface

Not really. It's a wrapper for an array, giving it the same semantics as an aggregate class - including the ability to copy and move it.

how can an std::array move-construct its elements?

In exactly the same way as any other aggregate. Its implicit move-constructor will move-construct all its members, including the elements of any member arrays.

Can I do the same with an ordinary array?

Only if you wrap it in a class type, as std::array does.

Outras dicas

Moving a std::array is different from moving a std::vector. When moving one std::vector into another, it's (sometimes*) possible to simply re-target the internal pointers and avoid manipulating the elements at all.

With std::array, this is of course not possible - its elements have automatic storage duration, they are literally contained inside the object. However, each individual one of them can still be moved, and that's what the move operations on std::array do**.

* Assuming the allocators are compatible and don't prohibit this operation

** That's also what you get with std::vector when the buffer can't just be re-owned by the destination vector.

The default move constructor for a (non-union) class performs a member-wise move. Moving a raw array data member means moving each of the array's elements, see [class.copy]/15.

Therefore, you can move a raw array by putting it inside a class:

struct wrap
{
    std::string arr[25];
};

auto w = wrap();
auto m = std::move(w); // moves the 25 `std::string`s

You can also manually invoke the move constructor of the elements, for example:

std::string a[3] = { /*...*/ };
std::string b[3] = {std::move(a[0]), std::move(a[1]), std::move(a[2])};

It is not specified if std::array contains a raw array. However, it does contain data members of the value_type, since it's guaranteed to be an aggregate. Those data members will be moved as described above when invoking the move constructor.

If the data members of a std::array are not MoveConstructible, instantiating its move constructor will fail.

You can do it using "placement new". You'll find plenty of questions on placement new already answered with many further details.

This one looks like it has a complete example:

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top