unique_ptr, shared_ptr, weak_ptr best practices

Started by
13 comments, last by King Mir 10 years, 4 months ago

[background=#fafbfc]“When these shared pointers get assigned to either default constructor or NULL, they allocate a reference counter and then free it when scope ends since they are just temporaries.”[/background]

Not true, they allocate nothing until used Whatever broken implementation you had might have done this, but it is not how it is supposed to work.

Actually Spiro's statement was half correct. When you default construct a boost::shared_ptr, no additional control structure is allocated. When you construct it with nullptr, a control structure is indeed allocated, and the deleter is called on that pointer. That is usually not a problem (because 'delete nullptr;' is safe), but calling some custom deleters is not safe (like GDALClose).
I haven't checked that with std::shared_ptr but I would assume their semantics are identical with boost::shared_ptr.
Advertisement

Not true, they allocate nothing until used Whatever broken implementation you had might have done this, but it is not how it is supposed to work.

Actually Spiro's statement was half correct. When you default construct a boost::shared_ptr, no additional control structure is allocated. When you construct it with nullptr, a control structure is indeed allocated, and the deleter is called on that pointer.


Actually we are all entirely correct (except for one reference to how things are supposed to work).
It’s up to the implementation, which is one of the scariest things about it and one of the biggest reasons to stay away (that and the atomic handling of the reference counters).



Whatever broken implementation you had might have done this, but it is not how it is supposed to work.

Actually, it’s the most recent version of the PlayStation Vita SDK, with C++11 support, and is what I am currently using, because what choice do I have?
But the standard doesn’t define implementation details, so there is no real how it is supposed to work, other than by conforming to the functionality specified by the standard.

So it’s reason enough to stay away from shared_ptr in general just because you don’t have guarantees on how it is implemented, but there is one extremely major issue in terms of performance that is true for all implementations (as the standard specifies that multi-threaded access to a shared pointer is built-in) which is also cause to stay away: Atomic reference counting.

Boost and std::shared_ptr are bottlenecks.

That article does not discuss the allocation overhead, but the overhead in atomic increments and decrements necessary for a standard-compliant shared_ptr to adhere to the, “All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of the same object,” specification.

All-in-all you don’t really win with std::shared_ptr or boost::shared_ptr.

It’s better to roll 2 of your own (one for single-threaded access and one for multi-threaded access) so that:

  1. You are sure of the implementation details.
  2. You don’t waste cycles on atomic operations when not necessary.

L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

I think L. Spiro has a point that shared pointers can be imperfectly tuned to particular uses of them, which do not use the full gamut of features a shared pointer allows. If you don't need all of shared pointer's features, and the code is performance critical, then rolling your own smart pointer may be an optimization.

The simpler alternative is to not share ownership, use unique_ptr in the cache and only give out normal references that are documented to be single use and not to be saved for longer. That avoids everyone creating their own shared pointers, which are quirky, possibly bugged, more easily misused or possibly even worse than the standard one.

The simpler alternative is to not share ownership, use unique_ptr in the cache and only give out normal references that are documented to be single use and not to be saved for longer. That avoids everyone creating their own shared pointers, which are quirky, possibly bugged, more easily misused or possibly even worse than the standard one.

That would mean you could never release resources, except perhaps on the manager's destruction, because you have no way of knowing when a managed object is no longer in use. It would be more flexible to have a custom handle to the resource.

Also, if you're going to the trouble to write a resource manager, it may make more sense to make a memory pool than using an array of unique pointers pointing to disparate memory.

This topic is closed to new replies.

Advertisement