13

With shared_ptr included in c++11, one could achieve a semi garbage-collected enviroment. Does the (inflationary?) usage come along with some disadvantages?

I could imagine a class model, where you create a class in which you typedef your class at the end as a shared_ptr to abbreviate the syntax.

/////////////////
//// MyClass ////
/////////////////

#include <memory>

class MyClass {
public:
    Myclass();
};

typedef std::shared_ptr<MyClass> SharedMyClass;

///////////////////////
//// Example Class ////
///////////////////////

class Example {
public:
    Example(): myClassObject(new MyClass()) {}
private:
    SharedMyClass myClassObject;
};
Mohit Kanwar
  • 2,962
  • 7
  • 39
  • 59
Matze
  • 533
  • 7
  • 16
  • 1
    Related [What's the overhead from shared_ptr being thread-safe?](http://stackoverflow.com/q/25780826/1708801) – Shafik Yaghmour Dec 01 '14 at 20:53
  • 8
    IMO, don't use a typedef for a type that is already so readable. It just makes another name for your readers to learn. – dlf Dec 01 '14 at 20:54
  • Abbreviating is just a personal style i like, and it follows a simple convention – Matze Dec 01 '14 at 20:56
  • @dlf indeed it is readable, but it is clunky/chunky considering one has to write a fast code example – Matze Dec 01 '14 at 20:58
  • 1
    Related [The cost of passing by shared_ptr](http://stackoverflow.com/questions/2502394/the-cost-of-passing-by-shared-ptr) – R Sahu Dec 01 '14 at 21:26

3 Answers3

13

Of course there are disadvantages: you require extra memory to maintain a reference count, and every time you copy or destroy a shared_ptr instance this reference count has to be incremented and decremented. If your program uses multiple threads then the manipulation of the reference count has to be done in a thread-safe manner, which can add some additional overhead, the magnitude of which depends on the implementation.

Whether or not this overhead impacts your program in an overall negative way depends on the details of your program. Generally you should only use std::shared_ptr for resources that truly need to be shared, because it can be somewhat arbitrary which object will need them last. In other cases, a single point of ownership is usually easier to maintain because you know exactly how long each resource will be alive.

Additionally, you need to be aware that std::shared_ptr is not a panacea for object lifetime management. In particular, if you have two objects that each own an std::shared_ptr to the other, the objects have cyclic ownership and will never be automatically deleted unless you first break the cycle by invoking reset() on one of them.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • And don't forget that `shared_ptr` is a template. If you use `shared_ptr`s to many different types, that can add up to a substantial amount of code. – dlf Dec 01 '14 at 20:55
  • 3
    Not to mention the possibility of circular references, which isn't actually solved with the `std::shared:ptr<>` _garbage collection_. – πάντα ῥεῖ Dec 01 '14 at 20:55
  • 1
    @dlf Indeed, though I expect any decent optimizing compiler would inline nearly every member function, especially `operator*` and `operator->` which are likely to be the most commonly used. – cdhowie Dec 01 '14 at 20:56
  • @πάνταῥεῖ That is a good point to bring up; I will edit it into my answer. – cdhowie Dec 01 '14 at 20:57
  • 2
    @cdhowie Well, when writing this it came to mind such situations can be solved using `std::weak_ptr`'s, but you'll have to know this pitfall in advance. It's not obvious. – πάντα ῥεῖ Dec 01 '14 at 20:59
  • @πάνταῥεῖ Yeah my original edit included `std::weak_ptr` but I removed that because using it to break cyclic references can cause even more obscure problems... Generally that calls for revisiting the object model design. – cdhowie Dec 01 '14 at 21:01
  • What obscure problems? I know I'm late to the party, but isn't that exactly the point of using a weak pointer? Ensuring against retain cycles, so that both objects can have pointers to eachother, but only one of them counting as strong, meaning that the class that is pointed to weakly is able to be released due to 0 strong pointers pointing at it, while the second will be released when the first class is released (being the only class strongly pointing to it)? – Sti May 08 '21 at 22:37
  • @πάνταῥεῖ **You can't fix a lack of ownership design with a system of "weak" variants of anything** (`shared_ptr` system, normal Java references system, etc. changed to use weak variants). You will really have to redo the analysis. Because **weak variants only break cycles by breaking basic guarantees of normal (strong) variants**. – curiousguy Jan 30 '23 at 16:36
4

One other thing worth mentioning is that you need to be very careful when designing your APIs with std::shared_ptr.

The obvious advantage over a raw pointer is the automatic memory management (with the cyclic ownership gotcha) but other problems/questions remain. When the resource is shared, you're giving up (to some extent) control and the ability to reason about your code.

Can I modify the object given that I might not be the only one holding onto it?

You change the object and the change reflects to the whole system. The larger the system, the less obvious are the implications and it's harder to prove that it's in fact safe to do. Sean Parent often says that a shared ptr is in fact as good as a global variable.

Jiří Pospíšil
  • 14,296
  • 2
  • 41
  • 52
  • Modifying shared data in a concurrent environment is a code smell anyway, `shared_ptr` doesn't make it any better or worse than doing the same thing without `shared_ptr` – Jonathan Wakely Dec 02 '14 at 00:04
  • shared_ptr deals with object lifespan, not concurrency. Just because a pointer is held in a shared_ptr doesn't mean that the object being pointed to will be touched in multiple threads. – Andre Kostur Dec 02 '14 at 01:09
  • @JonathanWakely The shared data might be a thread safe queue and the modifying operation "add an item", all of which is fine and common. The point was that when the resource is shared (not necessarily through a `std::shared_ptr`), it's harder to verify the correctness of the operation whatever it might be. – Jiří Pospíšil Dec 02 '14 at 07:49
  • @AndreKostur Not my point really but I've deleted the sentence to avoid further confusion. – Jiří Pospíšil Dec 02 '14 at 07:49
1

If performance is important I would not use std::shared_ptr. For example, to sort an array with real pointers is 5 times faster than to sort with shared pointers.

On the other hand shared pointer do not avoid all troubles with garbage leaks in case of circular references. Of course, this can be solved with weak_ptr, but what I mean is, that shared pointer need also be handled carfully.

I prefer to use shared_ptr for static elements, because static elements are not deleted by a destructor of a class.

hugo24
  • 1,089
  • 13
  • 21
Walter
  • 27
  • 1
  • 5