Related
As far as I understand, C++14 introduced std::make_unique because, as a result of the parameter evaluation order not being specified, this was unsafe:
f(std::unique_ptr<MyClass>(new MyClass(param)), g()); // Syntax A
(Explanation: if the evaluation first allocates the memory for the raw pointer, then calls g() and an exception is thrown before the std::unique_ptr construction, then the memory is leaked.)
Calling std::make_unique was a way to constrain the call order, thus making things safe:
f(std::make_unique<MyClass>(param), g()); // Syntax B
Since then, C++17 has clarified the evaluation order, making Syntax A safe too, so here's my question: is there still a reason to use std::make_unique over std::unique_ptr's constructor in C++17? Can you give some examples?
As of now, the only reason I can imagine is that it allows to type MyClass only once (assuming you don't need to rely on polymorphism with std::unique_ptr<Base>(new Derived(param))). However, that seems like a pretty weak reason, especially when std::make_unique doesn't allow to specify a deleter while std::unique_ptr's constructor does.
And just to be clear, I'm not advocating in favor of removing std::make_unique from the Standard Library (keeping it makes sense at least for backward compatibility), but rather wondering if there are still situations in which it is strongly preferred to std::unique_ptr
You're right that the main reason was removed. There are still the don't use new guidelines and that it is less typing reasons (don't have to repeat the type or use the word new). Admittedly those aren't strong arguments but I really like not seeing new in my code.
Also don't forget about consistency. You absolutely should be using make_shared so using make_unique is natural and fits the pattern. It's then trivial to change std::make_unique<MyClass>(param) to std::make_shared<MyClass>(param) (or the reverse) where the syntax A requires much more of a rewrite.
make_unique distinguishes T from T[] and T[N], unique_ptr(new ...) does not.
You can easily get undefined behaviour by passing a pointer that was new[]ed to a unique_ptr<T>, or by passing a pointer that was newed to a unique_ptr<T[]>.
The reason is to have shorter code without duplicates. Compare
f(std::unique_ptr<MyClass>(new MyClass(param)), g());
f(std::make_unique<MyClass>(param), g());
You save MyClass, new and braces. It costs only one character more in make in comparison with ptr.
Every use of new has to be extra carefully audited for lifetime correctness; does it get deleted? Only once?
Every use of make_unique doesn't for those extra characteristics; so long as the owning object has "correct" lifetime, it recursively makes the unique pointer have "correct".
Now, it is true that unique_ptr<Foo>(new Foo()) is identical in all ways1 to make_unique<Foo>(); it just requires a simpler "grep your source code for all uses of new to audit them".
1 actually a lie in the general case. Perfect forwarding isn't perfect, {}, default init, arrays are all exceptions.
Since then, C++17 has clarified the evaluation order, making Syntax A safe too
That's really not good enough. Relying on a recently-introduced technical clause as the guarantee of safety is not a very robust practice:
Someone might compile this code in C++14.
You would be encouraging the use of raw new's elsewhere, e.g. by copy-pasting your example.
As S.M. suggests, since there's code duplication, one type might get changed without the other one being changed.
Some kind of automatic IDE refactoring might move that new elsewhere (ok, granted, not much chance of that).
Generally, it's a good idea for your code to be appropriate/robust/clearly valid without resorting to language-laywering, looking up minor or obscure technical clauses in the standard.
(this is essentially the same argument I made here about the order of tuple destruction.)
Consider
void function(std::unique_ptr(new A()), std::unique_ptr(new B())) { ... }
Suppose that new A() succeeds, but new B() throws an exception: you catch it to resume the normal execution of your program. Unfortunately, the C++ standard does not require that object A gets destroyed and its memory deallocated: memory silently leaks and there's no way to clean it up. By wrapping A and B into std::make_uniques you are sure the leak will not occur:
void function(std::make_unique(), std::make_unique()) { ... }
The point here is that std::make_unique and std::make_unique are now temporary objects, and cleanup of temporary objects is correctly specified in the C++ standard: their destructors will be triggered and the memory freed. So if you can, always prefer to allocate objects using std::make_unique and std::make_shared.
I was reading Top 10 dumb mistakes to avoid with C++11 smart pointer.
Number #5 reads:
Mistake # 5 : Not assigning an object(raw pointer) to a shared_ptr as
soon as it is created !
int main()
{
Aircraft* myAircraft = new Aircraft("F-16");
shared_ptr<aircraft> pAircraft(myAircraft);
...
shared_ptr<aircraft> p2(myAircraft);
// will do a double delete and possibly crash
}
and the recommendation is something like:
Use make_shared or new and immediately construct the pointer with
it.
Ok, no doubt about it the problem and the recommendation.
However I have a question about the design of shared_ptr.
This is a very easy mistake to make and the whole "safe" design of shared_ptr could be thrown away by very easy-to-detect missuses.
Now the question is, could this be easily been fixed with an alternative design of shared_ptr in which the only constructor from raw pointer would be that from a r-value reference?
template<class T>
struct shared_ptr{
shared_ptr(T*&& t){...basically current implementation...}
shared_ptr(T* t) = delete; // this is to...
shared_ptr(T* const& t) = delete; // ... illustrate the point.
shared_ptr(T*& t) = delete;
...
};
In this way shared_ptr could be only initialized from the result of new or some factory function.
Is this an underexploitation of the C++ language in the library?
or What is the point of having a constructor from raw pointer (l-value) reference if this is going to be most likely a misuse?
Is this a historical accident? (e.g. shared_ptr was proposed before r-value references were introduced, etc) Backwards compatibility?
(Of course one could say std::shared_ptr<type>(std::move(ptr)); that that is easier to catch and also a work around if this is really necessary.)
Am I missing something?
Pointers are very easy to copy. Even if you restrict to r-value reference you can sill easily make copies (like when you pass a pointer as a function parameter) which will invalidate the safety setup. Moreover you will run into problems in templates where you can easily have T* const or T*& as a type and you get type mismatches.
So you are proposing to create more restrictions without significant safety gains, which is likely why it was not in the standard to begin with.
The point of make_shared is to atomize the construction of a shared pointer. Say you have f(shared_ptr<int>(new int(5)), throw_some_exception()). The order of parameter invokation is not guaranteed by the standard. The compiler is allowed to create a new int, run throw_some_exception and then construct the shared_ptr which means that you could leak the int (if throw_some_exception actually throws an exception). make_shared just creates the object and the shared pointer inside itself, which doesn't allow the compiler to change the order, so it becomes safe.
I do not have any special insight into the design of shared_ptr, but I think the most likely explanation is that the timelines involved made this impossible:
The shared_ptr was introduced at the same time as rvalue-references, in C++11. The shared_ptr already had a working reference implementation in boost, so it could be expected to be added to standard libraries relatively quickly.
If the constructor for shared_ptr had only supported construction from rvalue references, it would have been unusable until the compiler had also implemented support for rvalue references.
And at that time, compiler and standards development was much more asynchronous, so it could have taken years until all compiler had implemented support, if at all. (export templates were still fresh on peoples minds in 2011)
Additionally, I assume the standards committee would have felt uncomfortable standardizing an API that did not have a reference implementation, and could not even get one until after the standard was published.
There's a number of cases in which you may not be able to call make_shared(). For example, your code may not be responsible for allocating and constructing the class in question. The following paradigm (private constructors + factory functions) is used in some C++ code bases for a variety of reasons:
struct A {
private:
A();
};
A* A_factory();
In this case, if you wanted to stick the A* you get from A_factory() into a shared_ptr<>, you'd have to use the constructor which takes a raw pointer instead of make_shared().
Off the top of my head, some other examples:
You want to get aligned memory for your type using posix_memalign() and then store it in a shared_ptr<> with a custom deleter that calls free() (this use case will go away soon when we add aligned allocation to the language!).
You want to stick a pointer to a memory-mapped region created with mmap() into a shared_ptr<> with a custom deleter that calls munmap() (this use case will go away when we get a standardized facility for shmem, something I'm hoping to work on in the next few months).
You want to stick a pointer allocated by into a shared_ptr<> with a custom deleter.
With the new standard, there are new ways of doing things, and many are nicer than the old ways, but the old way is still fine. It's also clear that the new standard doesn't officially deprecate very much, for backward compatibility reasons. So the question that remains is:
What old ways of coding are definitely inferior to C++11 styles, and what can we now do instead?
In answering this, you may skip the obvious things like "use auto variables".
Final Class: C++11 provides the final specifier to prevent class derivation
C++11 lambdas substantially reduce the need for named function object (functor) classes.
Move Constructor: The magical ways in which std::auto_ptr works are no longer needed due to first-class support for rvalue references.
Safe bool: This was mentioned earlier. Explicit operators of C++11 obviate this very common C++03 idiom.
Shrink-to-fit: Many C++11 STL containers provide a shrink_to_fit() member function, which should eliminate the need swapping with a temporary.
Temporary Base Class: Some old C++ libraries use this rather complex idiom. With move semantics it's no longer needed.
Type Safe Enum Enumerations are very safe in C++11.
Prohibiting heap allocation: The = delete syntax is a much more direct way of saying that a particular functionality is explicitly denied. This is applicable to preventing heap allocation (i.e., =delete for member operator new), preventing copies, assignment, etc.
Templated typedef: Alias templates in C++11 reduce the need for simple templated typedefs. However, complex type generators still need meta functions.
Some numerical compile-time computations, such as Fibonacci can be easily replaced using generalized constant expressions
result_of: Uses of class template result_of should be replaced with decltype. I think result_of uses decltype when it is available.
In-class member initializers save typing for default initialization of non-static members with default values.
In new C++11 code NULL should be redefined as nullptr, but see STL's talk to learn why they decided against it.
Expression template fanatics are delighted to have the trailing return type function syntax in C++11. No more 30-line long return types!
I think I'll stop there!
At one point in time it was argued that one should return by const value instead of just by value:
const A foo();
^^^^^
This was mostly harmless in C++98/03, and may have even caught a few bugs that looked like:
foo() = a;
But returning by const is contraindicated in C++11 because it inhibits move semantics:
A a = foo(); // foo will copy into a instead of move into it
So just relax and code:
A foo(); // return by non-const value
As soon as you can abandon 0 and NULL in favor of nullptr, do so!
In non-generic code the use of 0 or NULL is not such a big deal. But as soon as you start passing around null pointer constants in generic code the situation quickly changes. When you pass 0 to a template<class T> func(T) T gets deduced as an int and not as a null pointer constant. And it can not be converted back to a null pointer constant after that. This cascades into a quagmire of problems that simply do not exist if the universe used only nullptr.
C++11 does not deprecate 0 and NULL as null pointer constants. But you should code as if it did.
Safe bool idiom → explicit operator bool().
Private copy constructors (boost::noncopyable) → X(const X&) = delete
Simulating final class with private destructor and virtual inheritance → class X final
One of the things that just make you avoid writing basic algorithms in C++11 is the availability of lambdas in combination with the algorithms provided by the standard library.
I'm using those now and it's incredible how often you just tell what you want to do by using count_if(), for_each() or other algorithms instead of having to write the damn loops again.
Once you're using a C++11 compiler with a complete C++11 standard library, you have no good excuse anymore to not use standard algorithms to build your's. Lambda just kill it.
Why?
In practice (after having used this way of writing algorithms myself) it feels far easier to read something that is built with straightforward words meaning what is done than with some loops that you have to uncrypt to know the meaning. That said, making lambda arguments automatically deduced would help a lot making the syntax more easily comparable to a raw loop.
Basically, reading algorithms made with standard algorithms are far easier as words hiding the implementation details of the loops.
I'm guessing only higher level algorithms have to be thought about now that we have lower level algorithms to build on.
You'll need to implement custom versions of swap less often. In C++03, an efficient non-throwing swap is often necessary to avoid costly and throwing copies, and since std::swap uses two copies, swap often has to be customized. In C++, std::swap uses move, and so the focus shifts on implementing efficient and non-throwing move constructors and move assignment operators. Since for these the default is often just fine, this will be much less work than in C++03.
Generally it's hard to predict which idioms will be used since they are created through experience. We can expect an "Effective C++11" maybe next year, and a "C++11 Coding Standards" only in three years because the necessary experience isn't there yet.
I do not know the name for it, but C++03 code often used the following construct as a replacement for missing move assignment:
std::map<Big, Bigger> createBigMap(); // returns by value
void example ()
{
std::map<Big, Bigger> map;
// ... some code using map
createBigMap().swap(map); // cheap swap
}
This avoided any copying due to copy elision combined with the swap above.
When I noticed that a compiler using the C++11 standard no longer faults the following code:
std::vector<std::vector<int>> a;
for supposedly containing operator>>, I began to dance. In the earlier versions one would have to do
std::vector<std::vector<int> > a;
To make matters worse, if you ever had to debug this, you know how horrendous are the error messages that come out of this.
I, however, do not know if this was "obvious" to you.
Return by value is no longer a problem. With move semantics and/or return value optimization (compiler dependent) coding functions are more natural with no overhead or cost (most of the time).
Occasionally, for fleeting moments, I think auto_ptr is cool. But most of the time I recognize that there are much simpler techniques that make it irrelevant. For example, if I want to have an object freed automatically, even if an exception is thrown, I could new up the object and assign to an auto_ptr. Very cool! But I could have more easily created my object as a local variable, and let the stack take care of it (duh!).
Thus I was not too surprised when I found google C++ coding standards banning the use of auto_ptr. Google states that scoped_ptr should be used instead (if a smart pointer is needed).
I'd like to know if anyone, contrary to my experience, can give a solid reason(s) of when auto_ptr is the best or simplest thing to use. If not, then I suppose I will ban using it myself (following google's lead).
update: For those who expressed concern, no I am not adopting google standards. For example, against google advice, I agree exception-handling should be activated. I also like using preprocessor macros, such as the printable enum I made. It is just the auto_ptr topic that struck me.
update2: It turns out my answer comes from two of the responders below, and a note from Wikipedia. First, Herb Sutter did show a valid use (source-sink idiom and lifetime-linked object composition). Second, there are shops where TR1 and boost are not available or banned and only C++03 is allowed. Third, according to Wikipedia, the C++0x spec is deprecating auto_ptr and replacing it with unique_ptr. So my answer is: use unique_ptr if available to me (on all platforms in consideration) else use auto_ptr for the cases that Sutter depicts.
It's the simplest thing to use when you need a scoped or unique pointer and you are working in a strict C++03 environment with no access to a tr1 implementation or boost.
Herb Sutter can help you out on this one: http://www.drdobbs.com/184403837
While banning auto_ptr seems attractive, but there is one issue:
template <typename T>
some_smart_ptr<T> create();
What will you replace the some_smart_ptr placeholder with ?
The generic answer, shared_ptr, is only worth it if the ownership is truly shared, if the function grants the caller exclusive ownership of the resources, it's misleading at best (and a typical case of premature pessimization as far as I am concerned).
On the other hand, in C++03, no other form of smart pointer can deliver: it's impossible, without move semantics, to provide what we'd like here. auto_ptr or a naked pointer are the two logical contenders. But then a naked pointer exposes you to the risk of leaks if the caller is careless.
With C++0x, unique_ptr advantageously replace auto_ptr in every situation.
std::auto_ptr still has pointer semantics, so automatic (non-pointer) variables aren't a substitute. In particular, std::auto_ptr supports polymorphism and re-assignment. With stack variables you can use references for polymorphism, but references don't allow for re-assignment.
Sometimes std::auto_ptr will do just fine. For example, for implementing a pimpl. True, in the vast majority of cases boost' smart pointer library offers better choices for a smart pointer. But right now std::auto_ptr is a standard solution, whereas boost's smart pointers aren't.
Using auto_ptr as function return value you will enjoy no copiyng overhead and never have memory leak. std::auto_ptr<obj> foo() can be safely called in { foo(); } while obj *foo() cannot. boost::shared_ptr can solve this, but with higher overhead.
Also, some objects can't be created on stack because of memory constraints: thread stacks are relatively small. But boost::scoped_ptr is better in this case since it can't be accidentally released.
Well one reason would be that scoped_ptr is non-copyable, so it's safer to use and harder to make mistakes with. auto_ptr allows transfer of ownership (eg. by passing it another auto_ptr as a constructor parameter). If you need to think things like transferring the ownership, the chances are you're better off with a smart pointer like shared_ptr.
With the new standard coming (and parts already available in some compilers), the new type std::unique_ptr is supposed to be a replacement for std::auto_ptr.
Does their usage exactly overlap (so I can do a global find/replace on my code (not that I would do this, but if I did)) or should I be aware of some differences that are not apparent from reading the documentation?
Also if it is a direct replacement, why give it a new name rather than just improve the std::auto_ptr?
You cannot do a global find/replace because you can copy an auto_ptr (with known consequences), but a unique_ptr can only be moved. Anything that looks like
std::auto_ptr<int> p(new int);
std::auto_ptr<int> p2 = p;
will have to become at least like this
std::unique_ptr<int> p(new int);
std::unique_ptr<int> p2 = std::move(p);
As for other differences, unique_ptr can handle arrays correctly (it will call delete[], while auto_ptr will attempt to call delete.
std::auto_ptr and std::unique_ptr are incompatible in someways and a drop in replacement in others. So, no find/replace isn't good enough. However, after a find/replace working through the compile errors should fix everything except weird corner cases. Most of the compile errors will require adding a std::move.
Function scope variable:
100% compatible, as long as you don't pass it by value to another function.
Return type:
not 100% compatible but 99% compatible doesn't seem wrong.
Function parameter by value:
100% compatible with one caveat, unique_ptrs must be passed through a std::move call. This one is simple as the compiler will complain if you don't get it right.
Function parameter by reference:
100% compatible.
Class member variable:
This one is tricky. std::auto_ptrs copy semantics are evil. If the class disallows copying then std::unique_ptr is a drop in replacement. However, if you tried to give the class reasonable copy semantics, you'll need to change the std::auto_ptr handling code. This is simple as the compiler will complain if you don't get it right. If you allowed copying of a class with a std::auto_ptr member without any special code, then shame on you and good luck.
In summary, std::unique_ptr is an unbroken std::auto_ptr. It disallows at compile time behaviors that were often errors when using a std::auto_ptr. So if you used std::auto_ptr with the care it needed, switching to std::unique_ptr should be simple. If you relied on std::auto_ptr's odd behavior, then you need to refactor your code anyway.
AFAIK, unique_ptr is not a direct replacement. The major flaw that it fixes is the implicit transfer of ownership.
std::auto_ptr<int> a(new int(10)), b;
b = a; //implicitly transfers ownership
std::unique_ptr<int> a(new int(10)), b;
b = std::move(a); //ownership must be transferred explicitly
On the other hand, unique_ptr will have completely new capabilities: they can be stored in containers.
Herb Sutter has a nice explanation on GotW #89:
What’s the deal with auto_ptr? auto_ptr is most charitably characterized as a valiant attempt to create a unique_ptr before C++
had move semantics. auto_ptr is now deprecated, and should not be used
in new code.
If you have auto_ptr in an existing code base, when you get a chance
try doing a global search-and-replace of auto_ptr to unique_ptr; the
vast majority of uses will work the same, and it might expose (as a
compile-time error) or fix (silently) a bug or two you didn't know you
had.
In other words, while a global search-and-replace may "break" your code temporarily, you should do it anyway: It may take some time to fix the compile errors, but will save you a lot more trouble in the long run.