auto_ptr vs unique_ptr in containers & algorithms - c++

I understand auto_ptr has screwed up copy semantics and therefore is not safe for use in containers since copying one auto_ptr to another will make the source = NULL pointer (isn't this like move semantics anyway??). But then again, unique_ptr cannot be copied at all and can only transfer ownership. So, how is unique_ptr usable in containers and algorithms that need to use copy operations to copy and re-arrange elements?

There is an in-depth explanation of why auto_ptr is dangerous, while unique_ptr is not:
N1856 : Why deprecate auto_ptr?
The main argument is that in generic code, something that has the syntax of a copy, should be a copy, not a move:
template <class It>
void sort(It first, It last)
{
// ...
value_type pivot_element = *mid_point;
// ...
}
In the above example, the generic code is highly likely to have logic that demands that pivot_element and *mid_point be equivalent after the copy construction shown. This may or may not be generic code in the std::lib. It might be generic code you have written.
When value_type turns out to be a std::auto_ptr<T>, then the above code compiles, but the assumption that pivot_element == *mid_point fails. A run-time error follows.
When value_type turns out to be a std::unique_ptr<T>, then the above code fails at compile-time (because you can't copy a std::unique_ptr<T>). Thus use of std::unique_ptr<T> in preference to std::auto_ptr<T> effectively turns run time errors into compile-time errors.
Now it is also true that within the std::lib, algorithms such as sort have been respecified such that they are not allowed to copy value_type. So it actually is safe to sort a sequence of auto_ptr<T> now (using std::sort). However std::unique_ptr<T> completely replaces the functionality of auto_ptr<T>, and auto_ptr<T> is still dangerous to use in generic code that does use copying (unique_ptr<T> fails to compile when used in such generic code).
So unique_ptr is safer to use than auto_ptr because it refuses to compile when used with generic code that copies.

They don't need to use copy operations anymore in the vast majority of cases. Move-only types like unique_ptr are first-class citizens. That's why move semantics is such a great improvement for both performance and correctness.

Related

C++ - returning vector from function

Coming from a Java background, I am trying to understand pointers/references in C++. I am trying to return a vector from a function. Writing:
vector<char*> f(){
vector<char*> vec;
return vec;
}
would return the copy of the vector, correct? A better way would be to return a pointer to vector like this:
vector<char*>* f(){
vector<char*>* vec = new vector<char*>;
return vec;
}
Am I correct, or is this totally wrong?
In C++03 the returning by value most likely leads to RVO (Return Value Optimization) which will elide the unnecessary copy. In C++11 move semantics will take care of the copy.
So, why return by value in the first place? Because it prevents unnecessary objects with dynamic lifetimes. Your example code also doesn't respect any allocation policy a user of your function might want to use.
In general, returning a container is even in C++11 still a bad idea: It restricts users to that specific container as it is not possible to move across containers, only to copy. The standard library solves this problem with OutputIteratorS. Your algorithm would most likely be written as:
template<typename OutputIterator>
OutputIterator f(OutputIterator o);
This way you abstract away from the container and also circumvent the original problem.
You're wrong, you do not want to do this in C++. Pretty much every C++ compiler out there has what's called Named Return Value Optimization, which will (effectively) cause the vec to be moved, not copied, by allocating space for the return value on the stack, which is then basically constructed "in place". This eliminates the overhead.
The Wikipedia article on this gives a reasonable rundown.
Am I correct, or is this totally wrong?
This is totally wrong, at least in C++11 where move semantics exists, and as long as you do not need to create aliases of the value you return (which does not seem to be your case and, even if it were, would likely require the use of smart pointers rather than raw pointers).
Returning a vector by value is OK now. Most of the time, even in C++98, the compiler would elide the call to the copy constructor anyway (and to the move constructor in C++11). This is called the (Named) Return Value Optimization.
In C++11, all the containers of the Standard Library support move constructors, so even when a copy or move is not elided, returning a container by value is not expensive.

Can queue::pop return a value now?

I know std::queue::pop() returns void. For two reasons:
exception safety: something might throw after removing the element
to be able to return the value by reference
Fine.
Now if I understand the new C++11 move semantics correctly, the second is no longer a valid argument.
So... the only thing preventing std::queue to have a pop-like function returning the value lies in the possibility that the move constructor throws?
I have a hard time thinking of situations where such a move constructor would throw. Who knows of an example?
I guess the same goes for std::stack::pop(), std::vector::pop_front(), std::vector::pop_back(), std::deque::pop_front(), std::deque::pop_back(), std::list::pop_front(), std::list::pop_back() and what not.
There aren't many cases where std::move() can throw in the standard library but there are cases. For example, if the container uses a stateful allocator, its children also use this allocator, but it won't be moved to a result: this would rather get a default constructed version of an allocator (if I remove correctly). Given that the allocators are stateful this means that the object can't be moved and thus the move construction fails with an exception. Why does this type then have a move constructor? Well, because it might be instantiated with non-stateful allocator in which case moving won't throw. In addition, once we move to user defined classes we have no idea under which condition moving them might throw.
Using clever SFINAE techniques it would indeed be possible to have an atomic non-throwing pop_and_move() for just datatypes that implement no-throwing move or no-throwing copy.
There is even a noexcept() construct available to see if something might throw.
One of the new concepts in C++11 in particular that extends SFINAE is that if the body doesn't compile the function doesn't exist. Thus one could implement based on noexcept().
I would say for backward compatibility the function would need a new name, which therefore allows it to co-exist with the existing functionality of calling them separately, not breaking containers of types that do not have the semantics to allow it.
Another problem is, that not every class really benefits from moving, i.e., they might only have a copy ctor.
struct DontLikeMoves{
// some data, whatever...
DontLikeMoves(DontLikeMoves const& other){
// might throw, who knows!
// and this will even get called for rvalues
}
};

std::move vs std::auto_ptr?

What can I do with 'move' (r-value references) in C++11 what I can't with std::auto_ptr? (As I understand they are different implementations of one idea.)
And old question again: is std::auto_ptr so bad component?
C++98/03 has no notion of truly "movable" classes. auto_ptr is a class with transfer-on-copy-semantics, i.e. when you make a copy, the content of the original changes (note the copy constructor with non-const argument!). This is Bad. Such a class cannot be used in the standard containers.
C++11 introduces the concept of truly movable classes thanks the the newly added notion of rvalue references. The new unique_ptr, which replaces auto_ptr entirely, is no longer copyable at all, but instead it is movable. All standard containers have been updated to attempt to move objects if possible, so it is now possible to store move-only objects in standard containers. Other examples of object which are only movable but not copyable are mutexes, locks, threads and iostreams.
To hammer in the point, compare a hypothetical, broken, C++98 piece of code with the corresponding C++11 code:
std::auto_ptr<Foo> p1(new Foo);
std::vector< std::auto_ptr<Foo> > v1;
//v1.push_back(p1); // eeww, what is the state of p1 now? ERROR
std::unique_ptr<Foo> p2(new Foo);
std::vector<std::unique_ptr<Foo>> v2;
//v2.push_back(p2); // Error, copying is simply not allowed
v2.push_back(std::move(p2)); // explicit; mustn't read p2 after moving it
v2.emplace_back(new Foo); // even better ;-)
The problem with std::auto_ptr is that it has copy operations which works like move operations. Therefore algorithms which work with copy operations can work on auto_ptr, but they don't behave as expected, since copied from objects have changed. As such auto_ptr can't be used with STL containers, however code which tries to do so will compile, but fail to work at runtime.
std::unique_ptr on the other hand doesn't have copy operations, but is only moveable instead. Therefore algorithms which copy std::unique_ptr will fail to compile when they should operate on std::unique_ptr. If something uses move operations, it doesn't expect the source of the move operation to remain the same, so no confusion there.
So basically it comes down to the operations working as is expected for a C++ object (or not).
One big difference is rvalue references (and assorted move optimizations) are automatically inferred/deducted from the calling context, whereas you need to create auto_ptr's manually at the call site.
auto_ptr is fundamentally broken, and rvalue references aren't. It's just that simple.
What can I do with 'move' (r-value references) in C++11 what I can't
with std::auto_ptr?
The very most important benefit of move, unique_ptr, etc, over auto_ptr is what you can't do, but can with auto_ptr.
This link explains the rationale to the committee for deprecating auto_ptr. It contains this conclusion:
Conclusion:
One should not move from lvalues using copy syntax. Other syntax for
moving should be used instead. Otherwise generic code is likely to
initiate a move when a copy was intended.
For details on how this conclusion was reached, read the link.

c++ vector with strict ownership semantics

This is not a question about putting std::auto_ptr into std::vector.
Is there some vector equivalent of std::auto_ptr in std::, std::tr1:: or boost::? I use std::auto_ptr in function parameters and return values to decalre ownership semantics of these functions. But this way I can pass only single objects. As a temporary solution for vectors I have this:
std::auto_ptr<std::vector<std::tr1::shared_ptr<ClassExample> > > fx(....);
which, I suppose, by introducing boost, I will be able to change into this:
std::auto_ptr<std::vectro<boost::unique_ptr<ClassExample> > >f(...);
in order to define strict ownership passing, but it seems to be quite complicated. To simplify it, I can use
std::vector<boost::unique_ptr<ClassExample> > f(...);
as the price for deep copy of the vector is not high, but I am still curious if there is something that I can use like this:
auto_vector<ClassExample> f(...);
meaning that the function is releasing ownership of all the objects and the vector internal data array is not deeply copied.
There's a C++11 solution - it requires an implementation that provides r-value references and has a standard library updated to include move constructors and std::unique_ptr.
Just return std::vector<std::unique_ptr<T>> - that type can't be copied, as std::unique_ptr<T> isn't copyable. The compiler will either use the move constructor when returning, which will not invoke a deep copy or will apply the RVO and elide the construction of a new object.
Without any particular reason as to why you need to maintain a vector of pointers, the first solution would be to ditch all the complexity and go for the simple:
std::vector<Type> f();
Ownership of the objects is unique (the vector owns them), and while the code looks like it is copying the vector on return it will be optimized away in most cases.
If you need the objects inside the vector to be dynamically allocated due to some other requirement (objects must be allocated through a factory, they are pointers to derived types, or they cannot move due to vector growth -- code maintains references/pointers) that you are not showing then I would go for a boost::ptr_vector that will maintain ownership of the contained objects. Again, return by value:
boost::ptr_vector<Type> f();

custom allocator using move for vector of thread

I'm currently learning about concurrency in C++ and came across using a vector of threads, which I believe will be possible in C++0x. However, my current compiler doesn't appear to have an implementation of move-aware containers and so I get errors generated because std::thread::thread(const std::thread&) is deleted, ie I can only use the move constructor/move assignment with std::thread.
Am I correct in thinking I could circumvent this issue by writing a custom allocator using
void MyAllocator::construct (pointer p, reference val)
/* should be non-const reference to val because using move constructor? */
{
new ((void*)p) T (std::move(val));
}
rather than
void allocator::construct (pointer p, const_reference val)
{
new ((void*)p) T (val);
}
? Or some other variation on this theme (possibly using an overload of MyAllocator::construct).
NB: This is mainly intended to be a short-term educational exercise and well enough performing work around to play around with threads in containers. I'd only be using MyAllocator in this context. However, please also point me at any libraries that may have this implemented so I can have a poke around the source.
If your compiler doesn't provide a move-aware std::vector then you'll have to write your own specialization of std::vector<std::thread> rather than just provide a custom allocator. The whole C++03 vector interface relies on copying: push_back() copies elements in; resize() initializes the empty elements with a copy of the element passed as the second parameter (even if that is the default value of T()); resize(), reserve(), insert(), erase() and push_back() will copy elements if the vector needs reallocating, or elements otherwise need moving around, and so forth.
This is such a common problem that I've included such a specialization with my (commercial) just::thread implementation of std::thread.
The easiest way to circumvent the problem would be to allocate the threads on the heap and manipulate pointers to them.
Check the Boost Pointer Container library: boost::ptr_vector<std::thread> seems to me what you are looking for.
The requirement that std containers only take copyable objects has more to do with the C++03 container interfaces than it does with the allocator implementation.
For example
vector<T> b(100);
vector<T> a;
a=b;
assert(a==b);
The standard assures us a==b is true. However, if T were not copyable, then in the best case a=b will not compile, in the worst a=b is undefined. Furthermore,
a.push_back(T());
may cause a to allocate new space, and under the hood there are copies made to the new underlying storage from the old.
Furthermore, there is nothing in the C++03 standard that says an implementation actually has to call allocator.construct, and in fact many (gcc for example) do not.
The C++0x standard adds new member functions to the container interface for moveable types, and clarifies how things like operator= behave in their presence.
See www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2486.pdf