Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens if an object held by a smart pointer gets deleted elsewhere?

This question always troubles me especially when I'm programming with Qt. Since Qt uses Object Ownership trees, passing a pointer e.g. via myBoostSharedPtr.get() can implicitly transfer ownership. Now consider the case where some Qt Object gets destroyed and the whole Object Tree is destroyed but the smart-pointer is still alive e.g. as member of a different class. What happens if the smart-pointer gets deleted afterwards ? Double deletion with all the nasty consequences ? Do some smart-pointer implementations prevent this ?

like image 229
Martin Avatar asked Mar 02 '12 23:03

Martin


People also ask

Do smart pointers automatically delete?

Smart pointers are class objects that behave like built-in pointers but also manage objects that you create with new so that you don't have to worry about when and whether to delete them - the smart pointers automatically delete the managed object for you at the appropriate time.

What happens when a shared pointer goes out of scope?

The smart pointer has an internal counter which is decreased each time that a std::shared_ptr , pointing to the same resource, goes out of scope – this technique is called reference counting. When the last shared pointer is destroyed, the counter goes to zero, and the memory is deallocated.

Are unique pointers automatically deleted?

C++11 offers two smart pointer classes, shared_ptr and unique_ptr . The unique_ptr class implements exclusive ownership semantics. This means that a unique_ptr object will claim exclusive ownership of the object it points to. When the unique_ptr object goes away, it automatically deletes the owned object for you.

Can smart pointers leak memory?

Smart pointers allow you to forget about manual allocation and can help avoid most memory leaks. On managed platforms, an object gets destroyed when there are no references to it.


2 Answers

I'm so tempted to do a rant on the weaknesses of Qt's memory model where a lot of the API still accepts raw pointers with the expectation that the client allocates it while the QObject that accepted the pointer deletes it.

The answer to your question is undefined behavior. shared_ptr has no mechanism to detect if the pointer is deleted by something other than shared_ptr itself, so it will generally try to free the pointer a second time (calling delete on a dangling pointer). If you want to use shared_ptr, you have to stick with shared_ptr as the sole memory manager. This is true even for Qt's own QSharedPointer.

What I normally did to try to get my code reasonably exception-safe when using something like Qt was to use the now deprecated auto_ptr (unique_ptr replaces it and is much safer if you have C++11 available). It's the only place where I was ever tempted to use auto_ptr before, as it provides a release method.

unique_ptr<QListWidget> widget(new QListWidget(...));
// do stuff with the widget to set it up for your GUI
some_layout.addWidget(widget.release()); // <-- release ownership so that 
                                         // the layout now becomes responsible 
                                         // for memory management
// ^^ auto_ptr works above if we don't have C++11

If you need to keep a persistent pointer to your object after it is already being memory-managed by Qt (ex: a pointer to your widget after you inserted it into a layout), just use a regular pointer. There's not really much better you can do since Qt is now the memory manager for that object.

However, you can detect when the object is destroyed (and therefore when the pointer is invalidated) through the QObject::destroyed signal.

If you want to get really sophisticated, you could build a shared pointer type which only stores subclasses of QObject. Since QObject provides a destroyed signal, this kind of custom smart pointer could detect when QObject is destroyed through the destroy signal and avoid trying to delete the object a second time. However, it might get hairy relying on this signal in multithreaded code, and if you do implement a shared pointer, it can become quite a burden dealing with atomic reference counting, capturing a deletion function at the site the pointer is constructed (to avoid module boundary new/delete mismatches), etc.

like image 181
stinky472 Avatar answered Oct 15 '22 17:10

stinky472


Yes, most likely and No they don't and I can't see how they could. You have to rely on the contract that the thing you are passing the pointer to will not take ownership (unless the documentation states it), and if the latter, don't wrap it in a smart pointer on your side.

like image 36
Nim Avatar answered Oct 15 '22 15:10

Nim