Is it safe to use unique_ptr in stl collections?

I am confused with the ideas of unique_ptr and rvalue move.

Say we have two collections:

std::vector<std::auto_ptr<int>> autoCollection; std::vector<std::unique_ptr<int>> uniqueCollection; 

Now, I would expect the following to fail, as there is no information about what the algorithm does internally and possibly makes internal summary copies, etc., thereby tearing ownership away from auto_ptr:

 std::sort(autoCollection.begin(), autoCollection.end()); 

I understand it. And the compiler correctly prohibits this.

But then I do this:

 std::sort(uniqueCollection.begin(), uniqueCollection.end()); 

And it compiles. And I don’t understand why. I did not think that unique_ptrs could be copied. Does this mean that the rotation value cannot be accepted, so sorting is less efficient? Or is this turn actually a move that is actually just as dangerous as the auto_ptrs compilation and should be forbidden by the compiler?

I think I am missing some important information, so I look forward to someone giving me aha! moment.

+42
c ++ c ++ 11 unique-ptr auto-ptr
May 20 '10 at 18:17
source share
3 answers

I think this is more a matter of philosophy than technology :)

The main question is the difference between Move and Copy. I will not delve into the technical / standardized language, let's do it simply:

  • Copy: create another identical object (or at least one that MUST be equal to equal)
  • Move: take an object and place it in another place

As you said, it is possible to implement Move in the terms of Copy: create a copy in a new place and discard the original. However, there are two questions. One of them has performance, the second - objects used for RAII: which of the two should have ownership?

The proper Move constructor solves two issues:

  • It is clear which property has the property: new, as the original will be discarded
  • Thus, there is no need to copy the specified resources, which improves efficiency

The characters auto_ptr and unique_ptr are a very good illustration of this.

With auto_ptr , you have screwed-up copy semantics: the original and the copy are not compared the same. You can use it for semantics of Move, but there is a risk that you will lose the object that it points to somewhere.

unique_ptr , unique_ptr other hand, is exactly what: it guarantees the unique owner of the resource, which avoids copying and the inevitable delete problem that will follow. And without copies, compilation time is guaranteed. Therefore, it is suitable in containers if you are not trying to initialize a copy.

 typedef std::unique_ptr<int> unique_t; typedef std::vector< unique_t > vector_t; vector_t vec1; // fine vector_t vec2(5, unique_t(new Foo)); // Error (Copy) vector_t vec3(vec1.begin(), vec1.end()); // Error (Copy) vector_t vec3(make_move_iterator(vec1.begin()), make_move_iterator(vec1.end())); // Courtesy of sehe std::sort(vec1.begin(), vec1.end()); // fine, because using Move Assignment Operator std::copy(vec1.begin(), vec1.end(), std::back_inserter(vec2)); // Error (copy) 

Thus, you can use unique_ptr in the container (unlike auto_ptr ), but a number of operations will be impossible, since they involve copying, which the type does not support.

Unfortunately, Visual Studio can be quite weak in applying the standard, and it also has a number of extensions that you need to disable to ensure code portability ... do not use it to verify the standard :)

+50
May 21 '10 at 6:44 a.m.
source share

unique_ptr move using its move constructor. unique_ptr Movable, but not CopyConstructable.

There is an excellent article on raleue links here . If you have not read about them or are not embarrassed, look!

+11
May 20 '10 at 18:29
source share

std::sort can only work with move operations and without copying if at any time there is only one live copy of each object. This is a weaker requirement than working in place, since in principle you can temporarily distribute another array and move all objects during their reordering.

for example, when std::vector<std::unique_ptr<T>> exceeds its capacity, it allocates storage for a larger vector, and then moves all objects from the old storage to the new one. This is not an on-site operation, but it is absolutely correct.

As it turns out, sorting algorithms like quick-sort and heap-sort can actually work in place without difficulty. In quick sort mode, std :: swap is used internally, which is considered a move operation for both objects. When choosing a bar, one trick is to swap it for the first element in the range, so it will never be moved until the section is complete.

+7
Feb 20 '13 at 9:52
source share



All Articles