krispet krispet
krispet krispet

Reputation: 1678

How efficient smart pointers are?

I know, that std::shared_ptr uses reference counting, so it has copy&move semantics, on the other hand std::unique_ptr (hence the name unique) only has move semantics, so trying to copy it is a compile error.

However, its not quite clear for me how big of a deal is that. Can I simply use std::shared_ptr over std::unique_ptr in most cases, or should I use std::unique_ptr whenever possible, as it's far more efficient because it doesn't have to take care of reference counting?

Also, I know that smart pointers are useful when dealing with, for example exception safety, but are they a mean to generally replace traditional T* pointers? Is it a good programming practice to use smart pointers over traditional T* pointers whenever possible?

Upvotes: 3

Views: 2541

Answers (5)

Mircea Ispas
Mircea Ispas

Reputation: 20790

You should prefer values to std::unique_ptr, and std::unique_ptr to std::shared_ptr whenever possible, but not for performance reasons. Yes, there is some overhead when it comes to std::shared_ptr, as they use inside some form of atomic counter, but this is negligible for most applications.

The main reason to use std::unique_ptr is the uniqueness semantics - when you (or someone else) read(s) the code it's very clear the lifetime and the ownership of the object. This makes it more easy to reason about the code and find logical/performance issues.

PS: std::unique_ptr has no overhead compared to raw pointer, but it has some great advantages.

Upvotes: 1

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275730

shared_ptr means that the ownership rules surrounding the resource are complicated. Understanding them requires tracking down the lifetime of all shared_ptrs in the general case.

unique_ptr means that the ownership rules surrounding the resource are dead easy.

Both enforce a set of ownership rules, but the rules for unique_ptr are simple and local, the rules for shared_ptr are complex and non-local. If you are in a situation where you are choosing between the two casually, then you aren't treating lifetime issues with the gravity they deserve.

If you have a pointer-like resource whose lifetime should be controlled simply, or even at some central location (type-wise) with complex logic around it, use unique_ptr. The cost over a raw pointer is minimal, and it adds (enforced) documentation that this is the "owning" pointer to this resource.

If you must have a resource whose lifetime is the union of the lifetime of a bunch of other objects, all of whom have unrelated lifetimes, shared_ptr can be considered. If your situation is so complex that a loop could possibly be formed, then naive shared_ptr use is no longer a practical option.

shared_ptr and weak_ptr can also be used as a distributed lifetime notification system, where a central location stores a (mostly unique) shared_ptr, and clients store weak_ptrs. Local (non-stored) shared_ptrs are created from the weak_ptrs in order to check that the target resource still exists, then the resource is manipulated, then the local shared_ptr is discarded. The goal here is to make (in a non-language enforced way) a unique_ptr with weak shares, so reasoning about lifetime is only marginally harder than the unique_ptr case.

shared_ptr basically never "solves" the lifetime problem without you proving that it will solve your lifetime problems. It can make some parts of that proof marginally easier.

Upvotes: 0

Nemanja Trifunovic
Nemanja Trifunovic

Reputation: 24561

The rule of thumb is:

  1. If you can, use a stack based object directly or by a reference instead of using pointers.
  2. Else, if you don't have to deal with shared ownership (usually you don't) use unique_ptr - it is not only faster, but also safer (no circular references).
  3. Else, if you do have shared ownership, use shared_ptr

Raw pointers are OK in certain circumstances when they don't carry ownership - for instance as an input argument to a function:

void draw (const shape* sh) {
    sh->draw();
}

...
std::unique_ptr<shape> ptr(new triangle);
draw(ptr.get());

Upvotes: 6

dau_sama
dau_sama

Reputation: 4357

A shared_ptr has the extra cost of construction/destruction of the pointer itself, if passed to a function, plus the reference counting mechanism.

Do not listen to anyone that says either smart pointers are always the way to go, nor to people who say raw pointers are always better. There are cases where smart pointers make sense, and cases where raw pointers are preferable.

For a more detailed and comprehensive read, I'll suggest you to visit: http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/

It covers all the points you raised and it is an easy read for the most part.

Upvotes: 0

Nidhoegger
Nidhoegger

Reputation: 5232

The problem with the shared_ptr is, that, afaik, the reference counting is an atomic function, that means it not only counts the references, but also has locking functionality to ensure that the function is atomic. So at that point, yes, unique_ptr is better to use, when you only need move functionality.

Personally, I dont use shared_ptr alot, mostly normal pointers are enough. Imho smart pointers are only encourage getting lazy in memory management. I was in projects where smart pointers only caused race conditions when quitting the program, because nobody knew the order of destruction and these pointers referenced each others. For myself, I only use them if a lib of mine is putting pointers to the outside for which it is irrelevent when they get deleted (or in which order).

Upvotes: 3

Related Questions