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.
Related
I have a QTreeView with associated QStandardItemModel and QStandardItem's that fill the model. Then i also have a slot function that connects to clicked(QModelIndex) on the model and does some stuff. While building the model i would like to pass in some custom data to the QStandardItem's so that the slot function can do something with it. I managed to get this working through the method described here.
However i'm concerned about there being a possible memory leak with this method and what to do about it. If it does leak, i cant delete it from the associated slot function since the view will still be there and the user may click the same item again (and then point to a NULL reference) and im not totally sure about possible ways to enclose the pointer with a smart pointer because of the relationship with the Q_DECLARE_METATYPE(Object*) macro and how data is set to QStandardItemto
So does this cause a memory leak without an associated delete here and if it does, what are the best ways to get around this?
If you declare a pointer as metatype, Qt will internally manage the pointer alone, so it's your responsibility to ensure that the object is deleted in due time (by deleting it manually and clearing references to it or assiging a parent to it and ensuring the parent is deleted. You can avoid memory leaks by using value-based metatype, e.g. Q_DECLARE_METATYPE(MyClass). However MyClass should have copy constructors so QObject will not do. You can also use shared pointers: Q_DECLARE_METATYPE(QSharedPointer<QObject*>). Qt will internally keep shared pointers and delete them when appropriate view items are removed, so the underlying object will be deleted if your code doesn't contain another shared pointers to it. Refer to QSharedPointer documentation to learn how to use it correctly.
It's rather not a question "how to do it" it's rather "how to do it the right way"
I'm developing an editor in Qt where different widgets display the children and its (member) variables. Each of these widgets should hold a reference/pointer to the edited child to display and change their member variables.
The first attempt was the old ANSI C way I learned (and still kinda stuck in) with simple raw pointer to the used objects. It works fine but since the C++11 standard supports smart pointer and using them is recommended I'm trying to use them.
The problem is, I'm not quite sure what's the "best way" to use them in this case...
After reading Smart Pointers: Or who owns you baby? and Which kind of pointer do I use when? and a few others I came to different conclusions:
The first is to use a*unique_ptr since the edited object is clearly the owner which creates and also deletes its children. The widgets are simply referring to the child to show or change them.
The problem is how should the widgets refer to the child...
for now I'm simply still using a raw pointer I got with the get() method of the unique_ptr but this seems kinda flawed to me.
I still can accidentaly call delete on the pointer and cancel the benefits of the smart pointer.
The second approach is to use a shared_ptr because many objects refer to the child and edit it. Also accidentaly deleting it in one widget would do no harm because it is still owned by other objects.
The problem is they own it. When I want to delete it from the edited object I also have to signal all widgets to delete it before it is really gone. (this again seems flawed and error-prone)
I'm not really content with both ways. Is there a clean(er) way to point to the unique_ptr child of the object? Or am I missing a completely different and better approach to this problem?
Your use case doesn't translate directly to requirements (what if someone else deletes the widget while you're editing it?) but I'll assume you don't need anything beyond a naked pointer.
The Standard Library does not provide any strict pointer-observer class. Among observer entities:
Nullable, mutable pointers of native type (T *)
Non-nullable, non-mutable references of native type (T &)
Non-nullable, mutable references/proxies of class type (std::reference_wrapper<T>)
Nullable, self-validating, mutable pointers to managed objects (std::weak_ptr<T>)
If you want a non-nullable, mutable pointer to a non-managed object, which is a fairly reasonable thing to want, you can roll your own.
But naked pointers aren't that bad. The only difference is that it can be nullptr, and that it doesn't have a nice, long, explicit name inside namespace std.
You want to use a shared_ptr in place of your unique_ptr and weak_ptr's in place of your raw pointers. This will give exactly what you're after. The weak_ptr's will not interfere with the edited object's ability to delete the underlying object.
If you are using Qt, you might consider using the Qt smart pointers instead of std:: smart pointers:
QShardPointer and QWeakPointer
or for QObjects:
QPointer (or QWeakPointer, esp in Qt4)
or to achieve copy-on-write data sharing, Qt container and QString style:
QSharedDataPointer
There are other pointer classes too, but some of the above are most likely to do what you want. Also important, if you have your data in Qt container classes, QStrings or such, they handle their own memory with copy-on-write semantics, and should generally be passed around as plain values (sometimes as references) instead of pointers.
But most importantly, do not use std::unique_ptr or std::shared_ptr with QObjects which have parents, because if the parent deletes the child first, then the std:: pointer will delete it again, crashing the program (other way will work ok, child will notify it's parent that it's deleted). In other words, there's a good chance of subtle bugs if you mix QObjects and std:: pointers, so just don't do it. It's not clear from your question if you are doing it, saying just in case.
There is a proposal for the world's dumbest smart pointer, which is a non-owning pointer. Basically, it is a T* that says "oh, and by the way, I don't claim any ownership over this data".
In this case, you have to manage that the observing/passive/dumb pointer gets reset if the unique_ptr goes away -- half manual lifetime management. Using a raw T* with a name that indicates it is non-owning works just as well prior to having the above.
There are benefits to doing the above, especially when you have objects with dependent lifetime.
If you do not, then a shared_ptr and weak_ptr works. Note, however, that anyone with a weak_ptr can create a new shared_ptr, which could extend the lifetime of the shared object beyond the original shared_ptr. This must happen, as there is otherwise a race condition whereby the user of the weak_ptr ensures its data is valid, then goes to use it, but before they do the shared_ptr's data is destroyed.
So the weak_ptr must either by able to prevent the shared_ptr from being destroyed (blocking in multi-threaded context, causing it to "fail" somehow in single-threaded contexts). "Fail" in this case consists of extending the lifetime, which solves both the multi-threaded and the single-threaded problem.
(The single threaded problem is that you verify the weak_ptr is good, do something that causes the shared_ptr to reset, then continue to want to use the weak_ptr's data without rechecking. Naively, it could be avoided with exceptions, but upon closer inspection you run into problems where you'd have to code all methods to check for deletion before accessing this and throw if this is deleted, a pretty harsh requirement!)
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.
Say I have an object and 10 pointers to it in several other objects of varying class types. if the object gets deleted, those pointers have to be set to null. normally I would interconnect the object's class with the classes which have pointers to it so that it can notify them it is being deleted, and they can set their pointers to null. but this also has the burden that the classes must also notify the object when THEY are deleted since the object will need a pointer to them as well. That way the object doesn't call dereference a dangling pointer when it destructs and attempts to notify the others.
I don't like this confusing web of crap and I'm looking for a better method.
Please note that auto pointers and shared pointers are not what I'm looking for - auto pointers delete their object when they destruct, and shared pointers do the same when no more shared pointers are pointing to it. What I'm looking for is a slick method for setting all pointers to an object to null when the object destructs.
"All problems in computer science can be solved by another level of indirection" -- David Wheeler
In your case, what will work very well is
std::shared_ptr<Object*> pp.
When you delete the object, set the shared Object* to null (e.g. *pp = 0;). All the other users are sharing the Object*, and will now see that it has become null. When all the users are gone, the memory used for the Object* itself will also be freed.
Auto pointers and shared pointers etc are basically just classes that handle this kind of stuff for you. But it sounds like you've got a slightly different requirement, so I think you should develop your own class to manager pointers and use that instead of the raw pointers. That way you should be able to get the slick functionality that you're looking for.
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.