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;
};
When we create an object with new operator in shared_ptr there will be two dynamic memory allocations that happen, one for object from the new and the second is the manager object created by the shared_ptr constructor. Since memory allocations are slow, creating shared_ptr is slow when compared to raw pointer.
A std::shared_ptr consists of a control block and its resource. Yes, the control block is thread-safe; but no, the access to the resource is not thread-safe. That means, modifying the reference counter is an atomic operation and you have the guarantee that the resource will be deleted exactly once.
Use shared_ptr to manage the lifetime of objects: Whose ownership is shared (multiple "things" want the object lifetime extended) Where the order of release of ownership is non-deterministic (you don't know in advance which of the owners will be "last" to release the object).
Indeed, once unique, a managed resource can't become shared by an action originating from another thread. The same pattern would be possible with shared_ptr if enable_shared_from_this did not exist. This is why IMHO, unique() has been removed from C++20: misleading.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With