Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a std::vector<T> movable if T is not movable?

I am getting a crash when trying to move a std::vector<T> where T is clearly not movable (no move constructor/assignment operator was defined, and it contains internal pointers)

But why would the move functions of vector want to call the move functions of T? It should not be necessary.

So my question from the title: Is a std::vector<T> movable if T is not movable?

like image 800
galinette Avatar asked Apr 10 '14 17:04

galinette


People also ask

Is std::vector moveable?

std::vector typically stores some pointers plus the allocator. When move-constructing a std::vector , only pointers and the allocator have to be moved. The elements don't need to be touched.

Is std :: array movable?

std::array is movable only if its contained objects are movable. std::array is quite different from the other containers because the container object contains the storage, not just pointers into the heap. Moving a std::vector only copies some pointers, and the contained objects are none the wiser.

How do you move a vector element?

You can't move elements from one vector to another the way you are thinking about; you will always have to erase the element positions from the first vector. If you want to change all the elements from the first vector into the second and vice versa you can use swap.

Does vector have a move constructor?

No. It doesn't call the move constructor. To call move constructor of element you will have to call std::move while pushing to vector itself.


2 Answers

  1. Yes, std::vector<T> is movable even if T is not movable. The left side merely takes ownership from the vector on the right, no elements are touched. (With one exception, listed in #2)

  2. The move assignment of a vector would only call the move constructor or move assignment of T if the and their allocators compare as equal and the left side's allocator's propagate_on_container_move_assignment is false. (Note that if your move constructor might throw or doesn't exist, the copy constructor will be used instead) However, it is unlikely that you are encountering either of these.

    Reworded: if propagate_on_container_move_assignment is true (it usually is), then the vector is always movable, and does so without touching individual elements. If it's false, but the allocators compare equal, the vector will be moved without touching individual elements. If it's false and the allocators compare inequal, the individual elements will be transferred. If a nothrow move assignment exists, that's used. Otherwise, if a copy constructor exists, that's used. Otherwise the throwing move assignment is used. If it's neither movable nor copiable, then that's undefined behavior.

  3. Having no move assignment operator defined, and the class containing internal pointers, does not mean your class is not movable. In fact, it sounds like the compiler thinks it is movable. If you want to disable moves, use T(T&&) = delete; and T& operator=(T&&) =delete, but I don't recommend that. Instead, add a correctly working move constructor and move assignemnt. They tend to be easy, and quite useful.
like image 114
Mooing Duck Avatar answered Nov 08 '22 18:11

Mooing Duck


Table 99 in [container.requirements.general] of n3797 about "Allocator-aware container requirements" says about move construction:

Requires: move construction of A shall not exit via an exception.

Where A is the allocator type. It does not require MoveInsertable for the value type.

The time complexity requirement is: "constant", btw.


std::vector typically stores some pointers plus the allocator. When move-constructing a std::vector, only pointers and the allocator have to be moved. The elements don't need to be touched.

like image 41
dyp Avatar answered Nov 08 '22 18:11

dyp