Im thinking of starting using smart pointers in my qt work.The thing that confuses me how smart pointers would go with Qt garbage collection. The whole Qt stands on idiom that child QObject constructs with QObject* parent as ctor argument and therefore enables garbage collection.
For example:
QWidget* mWidget = new QWidget(this);//Here we not only
//ensure that mWidget will be deleted
//when its parent is deleted, but also tell qt,
//that mWidget is not a window, but belongs to
//parent's layout
Now if i want to wrap mWidget into the smart pointer.
typedef QScopedPointer<QWidget> WidgPtr;
WidgPtr mWidget = WidgPtr(new QWidget(this));
But now when parent's dtor is called it will call delete on mWidget's pointer twice. First due to garbage collection, second when smart pointer dtor is called.
Of course we can construct mWidget without parent and then change some flags to turn off window behaviour or call setParent() (But then again mWidget will be deleted twice). But to me its too much to do such a complex initialization only to be able to use smart pointers instead of raw pointers.
Or maybe i miss something?
Thanks.
QScopedPointer and QSharedPointer are not aware of whether their target object lives or dies, so if you keep the smart pointer anywhere else than among member variables, then yes, in your case destructor might be called twice. That's why these kinds of smart pointers are badly suited for QObjects (but they can still be useful when your object doesn't have a parent).
If you need to keep a guarded pointer to QObject, use QPointer: it will become null once the object is destroyed, so you can delete it at any moment without fear of causing any mayhem. But remember that QPointer will NOT destroy referenced object in destructor. In most cases you should build hierarchies of QObjects and just let the ownership system clean up the memory.
Related
I am familiar with std::shared_ptr and std::weak_ptr and know how they work. However, I would like the std::shared_ptr to emit a callback, like a boost signal. This would allow std::weak_ptr, who still refer to the deleted object, to be cleaned up right in time.
Is there maybe already some smart pointer implementation, which will report the destruction?
Explanation
I think there might be a small design flaw in std::weak_ptrs, that can lead to false memory leaks. By "false memory leak" I mean an object, that is still accessible by the program, but whose reason of existence is not valid anymore. The difference to a true memory leak is, that the true memory leak is completely unknown by the program, while the false leak is just a part that wasn't cleaned up properly.
Another description can be found at codingwisdom.com
Use Watchers
One of the problems with freeing an object is that you may have done so while other things are still pointing at it. This introduces dangling pointers and crashes! To combat the evil of dangling pointers, I like to use a basic "watcher" system. This is not unlike the weak reference discussed above. The implementation is like this:
Create a base class "Watchable" that you derive from on objects that should broadcast when they're being deleted. The Watchable object keeps track of other objects pointing at it.
Create a "Watcher" smart pointer that, when assigned to, adds itself to the list of objects to be informed when its target goes away.
This basic technique will go a long way toward solving dangling pointer issues without sacrificing explicit control over when an object is to be destroyed.
Example
Let's say we implement the observer pattern using boost Boost Signals2. We have a class Observable, that contains one or more signals and another class Observer, that connects to Observable's signals.
What would happen to Observable's slots, when a observing Observer is deleted? When we do nothing, then the connection would point to nowhere and we would probably receive a segmentation fault, when emitting the signal.
To deal with this issue, boost's slots also offer a method track(const weak_ptr<void>& tracked_object). That means, if I call track and pass a weak_ptr to Observer, then the slot won't be called when the weak_ptr expired. Instead, it will be deleted from the signal.
Where is the problem? Let's we delete an Observer and never call a certain signal of Observable ever again. In this case, the tracked connection will also never be deleted. Next time we emit the signal it will be cleaned up. But we don't emit it. So the connection just stays there and wastes resources.
A solution would be: when owning shared_ptr should emit a signal when it is destroying it's object. This would allow other other objects to clean up right in time. Everything that has a weak_ptr to the deleted object might register a callback and false memory leaks could be avoided.
//
// create a C function that does some cleanup or reuse of the object
//
void RecycleFunction
(
MyClass * pObj
)
{
// do some cleanup with pObj
}
//
// when you create your object and assign it to a shared pointer register a cleanup function
//
std::shared_ptr<MyClass> myObj = std::shared_ptr<MyClass>( new MyClass,
RecycleFunction);
Once the last reference expires "RecyleFunction" is called with your object as parameter. I use this pattern to recycle objects and insert them back into a pool.
This would allow std::weak_ptr, who still refer to the deleted object,
to be cleaned up right in time.
Actually, they only hold weak references, which do not prevent the object from being destroyed. Holding weak_ptrs to an object does not prevent it's destruction or deletion in any fashion.
The quote you've given sounds to me like that guy just doesn't know which objects own which other objects, instead of having a proper ownership hierarchy where it's clearly defined how long everything lives.
As for boost::signals2, that's what a scoped_connection is for- i.e., you're doing it wrong.
The long and short is that there's nothing wrong with the tools in the Standard (except auto_ptr which is broken and bad and we have unique_ptr now). The problem is that you're not using them properly.
I want to use C++11 Smart Pointers in new projects, and encounter a problem. Many current projects still use raw pointers as parameters in their interface and have no interface for smart pointers, e.g. QMainWindow::setCentralWidget.
To keep type consistent, I have to pass the stored pointer from get() like this segment:
QMainWindow win;
std::shared_ptr<QWidget> scrollArea{ std::make_shared<QScrollArea>() };
// QScrollArea is a derived class of QWidget.
win.setCentralWidget(scrollArea.get());
But I can't make sure whether other methods in Qt execute operator delete on the stored pointer of scrollArea.
Will it cause memory leak or other problems if some methods in Qt do that?
I've checked the latest C++ Standard CD and found nothing on that. Seems it's an undefined behavior.
If doing this is an undefined behavior and dangerous, is there a safe way to use smart pointer(s) with the interface for raw pointer(s)?
There's no such way in the general case. For each "legacy" interface you want to use, you must read its documentation to see how it interacts with ownership (which is what std smart pointers encapsulate). A single object can only be managed by one ownership scheme.
With Qt in particular, it's definitely not safe to mix smart pointers and Qt management. Qt's parent/child relationship between QObjects includes ownership semantics (children are deleted when their parent is), so you cannot safely mix this with any other ownership scheme (such as std smart pointers).
Note that the Qt docs you link to explicitly state that "QMainWindow takes ownership of the widget pointer and deletes it at the appropriate time."
Unfortunately, if you are using an interface that uses raw pointers, you will need to consult the documentation to determine if the method does or does not take ownership of the provided pointer.
If the function takes ownership, then you must invoke .release() to transfer the ownership to the function. If the function does not take ownership, then you would pass the object with .get().
Will it cause memory leak or other problems if some methods in Qt do that?
It won't introduce a memory leak, since the memory is afterall released. However, since both QT and the shared_ptr would call delete on that memory, you would likely get some nice heap corruption (UB in general).
is there a safe way to use smart pointer(s) with the interface for raw pointer(s)?
Sure. Don't have unrelated entities manage the same memory. For that it is adavantegous to use unique_ptr instead of shared_ptr when possible. With unique_ptr you could call .release() to release the memory from the control of the smartpointer, thus giving you the ability to give control over to QT.
Of course you need check the documentation to see when you have to manage memory yourself and when QT will do it for you.
I don't think you should be doing any deleting with the QWidget.
http://qt-project.org/doc/qt-4.8/qmainwindow.html#setCentralWidget
Note: QMainWindow takes ownership of the widget pointer and deletes it
at the appropriate time.
If you have to use smart pointers, you can use a weak_ptr which won't own or destroy it.
If you are using an interface which takes raw pointers, you already have the problem that you must know who is responsible for the lifetime of those pointers.
Adding shared_ptr into the mix doesn't change this.
If the interface will possibly delete the object, then you cannot use std::shared_ptr safetly. std::shared_ptr must control the lifetime of its objects and there's no way around this (without adding another level of indirection)
You can however get some use out of std::unique_ptr. If an interface will not delete a pointer, you can safetly pass in ptr.get(). If an interface takes ownership of the lifetime of that object, pass in ptr.release() and you give up controlling the lifetime yourself.
All in, you can get some usefulness out of smart pointers even with a legacy codebase, but you've got to be a little careful.
But I can't make sure whether other methods in Qt execute operator delete on the stored pointer of scrollArea.
If the widget has a parent, then the QT's memory management will release that object. In that case you must not use a smart pointer, because your application will try to release it twice, and that is an undefined behaviour.
I noticed that when substituting raw pointers with shared_ptr in QT, my code does not work anymore.
For example, if instead of
QTreeWidgetItem* vItem(new QTreeWidgetItem(ItemTitle));
I use
std::shared_ptr<QTreeWidgetItem> vItem(new QTreeWidgetItem(ItemTitle));
then, either the program crashes or nothing is done (even if I use the .get() function to get the
raw pointer from the shared one later in my code). Does anybody knows what could be the cause?
Using shared pointer with Qt model items causes an ownership conflict: QTreeWidget takes ownership of any QTreeWidgetItem you pass to it. std::shared_ptr also owns its item. Both assume they can delete the item themselves and that nobody else will delete it behind their back.
In such situations, where Qt takes ownership of the pointers (other example: parent QObject taking ownership of its children), one cannot use std::shared_ptr/QSharedPointer at the same time. std::shared_ptr only works well when using std::shared_ptr and std::weak_ptr exclusively to hold pointers to that particular object.
According to the Qt documentation:
QObjects organize themselves in object trees. When you create a
QObject with another object as parent, the object will automatically
add itself to the parent's children() list. The parent takes ownership
of the object; i.e., it will automatically delete its children in its
destructor.
For me that implies when a QObject is being deleted, it goes through and calls delete on all the pointers it stores in its children list.
However, it is not necessary for children to be dynamically allocated, and it is perfectly legal to build QObject trees with stack allocated objects.
According to standard specifications, calling delete on a pointer that does not point to a dynamically allocated object is undefined behavior, which may result in anything from "nothing" to a program crash.
IMO it is unlikely for QObject, which is pretty much the backbone of the almost the entire collection of Qt classes to rely on something that could produce undefined behavior.
So, does QObject distinguish between stack and heap allocated children when deleting? And if so, how exactly?
However, it is not necessary for children to be dynamically allocated,
and it is perfectly legal to build QObject trees with stack allocated
objects.
No. See QObject::~QObject():
Warning: All child objects are deleted. If any of these objects are on
the stack or global, sooner or later your program will crash.
How does the dynamically allocated pointers in QT coding are destroyed because we don't write a specific destructor for them?
To expand on Neox's answer, Qt has two methods for object management:
QObject tree structure
Managed pointer classes
And the two don't really mix very well for reasons which will become apparent.
QObjects can either be 'free' or have a parent. When a QObject has its parent set (either by providing the QObject constructor with a pointer to another QObject, or by calling setParent()) the parent QObject becomes the owner of the child QObject and will make sure any of its children are destroyed when it is. There are also several methods available to inspect child/parent relationships.
A separate method of managing dynamically allocated objects are the managed pointer classes which this paper explains quite well. To summarise though:
"The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon destruction" and is therefore good when you need objects which have clear and obvious ownership and lifetime.
"The QSharedPointer class holds a strong reference to a shared pointer [and] will delete the pointer it is holding when it goes out of scope, provided no other QSharedPointer objects are referencing it" and is therefore good when ownership is not as clear cut, but you want to make sure it doesn't get lost and become a memory leak. QWeakPointer can be used to share the pointer without implying any ownership.
As you can see, some of the guarded pointer classes can be used with a QObject tree, but you should make sure you read and understand the documentation thoroughly before doing so or you may end up with a corrupt data structure.
The short answer is:
QObjects organize themselves in object trees. When you create a QObject with another object as parent, it's added to the parent's children() list, and is deleted when the parent is.
Qt has a good docu about object hierarchy and ownership within the framework. You can read it here