Someone over on Reddit asked the same thing. My reply:
You're exactly right. But there are multiple complications:
- unique_ptr and shared_ptr are only available in C++11 onwards, we're still to migrate to a new compiler
- auto_ptr is a joke [1]
- I've got to live with `delete` in our gargantuan codebase at work
- I could (and should) use boost's smart pointers, and indeed I do when possible. But I admit I sometimes even forget to use those and end up with naked pointers instead.
Promiscuous use of smart pointers is almost as bad a code smell as manually newing and deleting stuff. Ownership should be object lifetime, and it's really not hard to arrange member objects to make that work.
And if you really can't, and you need a container that automatically frees its contents when destroyed, just stick it in a STL vector.
Promiscuous use of shared pointers is a code smell.
std::unique_ptr (or its predecessor, boost:scoped_ptr if you don't have access to C++11) should be used all over the place. There are many reasons why you may not want by-value containment of objects, and std::unique_ptr gives you object-lifetime ownership of pointers.
The specific situation being addressed was C++03 code. But, sure; unique_ptr is harmless and mostly impossible to misuse. (Though again, to be fair, it provides little real value that the "stick it in a vector" trick didn't in 1998).
But aesthetically, I've learned to distrust any code that likes to throw objects around the design by pointer. It's untidy, and leads to needless abstraction and poor coupling. The time you spend trying to fit your objects into by-value composition is time you save later not having to untangle your knots of pointers.
The C++03 equivalent to unique_ptr is boost::scoped_ptr. It has some corner cases that are not as elegant as unique_ptr, but it was still good enough for Google for many years, until C++11 was greenlit in production.
You're missing the point. I like unique_ptr. But pointer composition in general is a smell, and unique_ptr is at best a patch around that.
The whole notion of having to carefully manage ownership via syntax (seriously: try explaining to a python programmer why they have to use this insane "unique" thing just to store a reference to something) instead of via structure (put the object inside its owner) is just vile, aesthetically. And it's something that C++ nuts tend to be really bad about.
Nullability - a scoped_ptr or unique_ptr can be null, a value object can never be.
Polymorphism - a value object is always exactly its static type, but you can substitute in different derived types for a unique_ptr. The previously-held object is automatically destroyed when you do this. This is essential for the State and Strategy patterns.
Reassignment/swap - reassigning a unique_ptr destroys its previous value and transfers ownership of the new one. Reassigning a value object invokes operator=. The former can (sometimes, not always) be faster than the latter - think about cases where you just want a quick pointer swap inside the object, rather than having to shuffle all the bits in a large struct around.
Release - unique_ptr has a member function to release ownership of the object, while this concept doesn't apply to value objects. Where might this be useful? Well, imagine trying to achieve exception safety inside a factory function with complex construction logic, and then transferring ownership to the caller. It's common to immediately assign the new object to a unique_ptr upon construction (so if an exception is ever thrown, it is destroyed properly), perform your logic, and then return ptr.release().
the following however will not work because RVO cannot be employed (the space occupied on the stack for the return value can't be shared with the source object)
std::unique_ptr<int> foo(bool b) {
std::unique_ptr<int> x(new int(42));
std::unique_ptr<int> y(new int(17));
return b ? x : y;
}
Wups, yeah, it occurs to me that a factory function would transfer ownership so a unique_ptr is a more appropriate return value.
You could imagine another example where the goal of the factory function is to construct an object and then set one of two or more other owned pointers to the value. You still want something to hold ownership of the pointer, but don't know its eventual home until after some complicated logic finishes, and don't want to pay the copy constructor cost. That might make a better illustration (or technically, you'd use operator= instead of release(), but same basic point).
The indirection and heap (de)allocation also imposes a slowdown, though. Have you actually experienced this to be worth it in some cases, or is this just a guess?
> Release
I don't think this is a valid reason...? This is a pretty common idiom for releasing value types:
You're exactly right. But there are multiple complications:
- unique_ptr and shared_ptr are only available in C++11 onwards, we're still to migrate to a new compiler
- auto_ptr is a joke [1]
- I've got to live with `delete` in our gargantuan codebase at work
- I could (and should) use boost's smart pointers, and indeed I do when possible. But I admit I sometimes even forget to use those and end up with naked pointers instead.
[1]: http://stackoverflow.com/a/111531/504611