Uninitialized move in std :: vector

I am using visual studio 2010, and its implementation of stl is dinkumware

I noticed that when the internal buffer of the vector grows, _Uninitialized_move is called. which is very similar to std :: uninitialized_copy.

  • for a scalar type, it will eventually redirect the memmove call
  • for a non-scalar type, it will call the constructor of the copy of the contained type.

I know that for a non-scalar type, bit copying is unsafe, but in this case they confuse me, because old objects will be destroyed very soon. it seems like a bit-wise way to handle all types is safe, and therefore we only need a free raw buffer after _Uninitialized_move. this saves many copy constructors and destructors for non-trivial objects.

so, is it safe to just move the contents for a non-scalar type?

+4
source share
3 answers

If you are completely sure that the objects that you are moving do not have pointers to each other (sub-objects included) - then just moving the contents in order. However, you cannot know this if you do not know how this type is developed internally. The only exception is that if the type is not larger than the pointer ( sizeof(Type) <= sizeof( void* ) ), then it is very unlikely to have pointers to objects in one container, so you can usually just move it around.

+4
source

In C ++ 11, there are many signs to know whether it is safe to perform bit operations or not.

In your case, I think you should use std::is_trivially_move_constructible<T> . These features are implemented using the built-in compiler functions (not portable, therefore, in the standard library), but they themselves are portable.

Therefore, the code should be akin to:

 template <typename T> void move_to(T* storage, T* begin, T* end) { if (std::is_trivially_move_constructible<T>::value) { memmove(storage, begin, (end - begin) * sizeof(T)); } else { for (; begin != end; ++begin, ++storage) { new (storage) T(std::move(*begin)); } } } 

And the compiler will optimize if at compile time depending on whether the type is a trivial movement constructive or not, and only leave an interesting branch.

+4
source

No. If they have pointers to each other, then a simple bitwise move will invalidate them.

+1
source

Source: https://habr.com/ru/post/1390386/


All Articles