Hacker Read top | best | new | newcomments | leaders | about | bookmarklet login

There's nothing more complicated about using unique_ptr than a raw pointer, it just expresses who's responsible for calling `delete` explicitly in code rather than implicitly through program flow.


sort by: page size:

"Most people" using new/delete with raw pointers = memory leaks and crashes, guaranteed.

unique_ptr and shared_ptr are really simple and incredibly useful. If you're too scared to use them, you should not be using C++ at all.


Totally agree. Recently used unique_ptr with a custom deleter is to consume a C library that requires heap allocation with its own alloc/free functions. No destructor!

Agreed. That problem existed even before unique_ptr though; there are still some APIs that I use that hand you back pointers that you may or may not need to manage yourself. If you do need to, then unique_ptr + custom deleter is the way to go!

> 3. New/delete will always be used in performance critical code but I think the point is that in general it's not a good practice.

There's zero runtime overhead to using std::unique_ptr - the compiler will inline the calls to delete you'd otherwise be writing by hand.


By default, unique_ptr calls delete.

It therefore still calls the destructor.

So this has literally no bearing on the problem. It doesn't help at all.


Unique_ptr offers many advantages:

1) Exception safety: what if you throw between your new and delete? Unique_ptr will clean up for you anyway and leave you in a stable state.

2) What if you forget to delete or your delete code never runs? Any of the many problems associated with explicitly writing delete can be non-issues with unique_ptr.

3) Clarity. When you see regular pointers in C or C++, it is never immediately clear who owns them. With unique_ptr, you don't have this problem because it doesn't look like a pointer. If you therefore see pointers, you know immediately they are non-owning.

4) Convenience functions like reset() on unique_ptr handle the release of the old and allocation of the new simultaneously. In general, the less code you have to write is often the better path to safety and maintainability.

5) Unique_ptr handle resources other than memory. It can be used to handle file streams, DB connections, etc and automatically close those also, if you provide a custom deleter function (which can just be a lambda, for elegance).

6) Unique_ptr is not copyable. This is important: if you own resources, it force you to consider this when you copy objects, and the compiler will force you to write your own copy constructor. Without this, it is easy to get into trouble if you forget these things with raw pointers.

7) Many syntactic improvements: i.e. unique_ptr will automatically call delete or delete[] based on what needs to happen, you can't accidentally get it wrong.

This is just a start list. The value of unique_ptr is considerable.


It's pretty stupid to compare a unique_ptr with a deleter that contains state to a pointer - obviously those two things are completely different and the unique_ptr contains way more information.

I agree with almost everything in your post, but I'm surprised about your comment that unique_ptr has overhead. Since unique_ptr is a single item struct with no vtable I'd expect no space overhead at all. Similarly, while it does need to run code in its destructor, I'd expect a trivial, non-virtual destructor like that to be reliably inlined and the result to be no worse than a manual call to delete. If that's not true, though, I'd definitely like to know, so please let me know if I've missed something.

To be clear: I'm not advocating for the use of `new` / `delete` over unique_ptr. But if you're creating a local object that never has to leave the current scope (or a member variable that's never moved in or out), there's no benefit to using a unique_ptr instead of creating the object directly on the stack or inline as part of your class, where the object's lifetime is bound to the scope, and your destructor is automatically run when its containing scope is cleaned up.

As an added bonus, you don't actually have to do a separate heap allocation.


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.

[1]: http://stackoverflow.com/a/111531/504611


For almost all use cases, the issues mentioned don't even come up. You create a unique_ptr with std::make_unique, or a shared_ptr with std::make_shared. It lives its entire life as that type, and when you no longer need it, you forget about it.

The issues in the article had me banging my head, because they aren't how smart pointers are used in practice. The only time that you would call release(), for example, is when you are passing a pointer into a pre-C++11 API. Once you have done so, you wouldn't be worrying about calling delete anyways, because you have transferred ownership.


You're missing out in a big way.

std::unique_ptr & std::shared_ptr are amazing. If you're still writing new & delete, you're just making things harder on yourself. I'll still use raw pointers in C++, but only the a borrowing context. It massively simplifies ownership. No more reading docs to try and guess if this pointer being passed in or returned needs to be freed or not. If I own it, it's a unique_ptr. If I'm giving it to someone else, it's a unique_ptr&&. If I'm letting something borrow it, it's a raw pointer or reference.

Or I'll make my own smart pointer containers for allocations with special lifecycles, like per-frame allocations from a custom arena allocation that must not be destroyed with delete/free.

Why try to remember all your lifecycle manually, which is incredibly error prone and no you're not immune to mistakes here, when you can compiler-enforce it instead?


unique_ptr is super useful for documenting the point in the code that owns a given object, and for providing some compile time protection against multiple deletions. (If you never write delete and only use unique_ptr, you have to do a relatively foolish thing to get double deletions.)

Without a custom deleter unique_ptr should have zero overhead.

You usually shouldn't use unique_ptr for C api stuff unless you really only need to free it.

Typically though there are custom delete/free API calls you need to make, and to use them with unique_ptr you have to pass that function pointer in as the second argument to the unique_ptr constructor.

At the very least you should have a C++ function that gives you the unique_ptr back that does the right thing; but at that point you almost might as well just make a class and give it member functions to map the C calls.


unique_ptr is pretty bad for performance as well. It is more complicated to use compared to raw pointers and encourages an OOP object-per-object piecemal code and data architecture. I've never seen a C++ program making use of unique_ptr that didn't give a strong smell of enterprise programming.

If you use smart pointers in your code (std::unique_ptr, std::shared_ptr), you will rarely have to call delete. A unique_ptr for example owns an object through a pointer; the pointer is automatically deleted when the unique_ptr goes out of scope. shared_ptr retains shared ownership through reference counting; the pointer is deleted when the reference count reaches zero.

Only use shared_ptr when you actually want shared ownership. If you stick to unique_ptr for owning references and then "borrow" that raw pointer in functions, then you get speed without sacrificing too much safety and still no new/delete.

You've never found a context in which unique_ptr is useful? I find this surprising. It basically removes a class of memory management bugs with heap allocated objects at a stroke.
next

Legal | privacy