I'm curently working on dialogs in an MFC application and I'm – admittedly – quite new to MFC.
Let's say I have class A (derived from CDialog) that uses class B (also derived from CDialog). Thus, A::OnInitDialog() calls the create(...) method of B.
I saw now that the destructor of class B contains
if ( GetSafeHwnd() )
{
DestroyWindow();
}
Is this okay? In my understanding it would be better to call B's DestroyWindow()method in A::OnDestroy(). Is that right?
Thanks for your help!
Oliver
One thing you may have noticed as you've delved in to MFC is that it is a wrapper API and not strictly object-orientated. Whereas we would like to use RAII (Resource Acquisition Is Initialisation), MFC does not create windows in its constructor. It does it, as you rightly point out, through the Create() method.
Therefore it makes more sense to me, given the way MFC works, To destroy B when A is being destroy (A::OnDestroy), so I think you're going down the right path.
Related
So, I've learned so far, that Qt releases the memory of all child objects when a parent object gets deleted. Also, one generally doesn't have to care about memory management for objects created on the stack (i.e. NOT as pointers).
Now, when I did the very good "AddressBook" tutorial, I found this in part 5:
AddressBook::AddressBook(QWidget *parent) : QWidget(parent)
{
dialog = new FindDialog;
}
Complete source is available:
addressbook.h
addressbook.cpp
finddialog.h
Here, dialog is a private member of AddressBook, and it is a pointer to a FindDialog. FindDialog inherits QDialog, but no this-Pointer is passed to the constructor (as seen above). No explicit destructor exists, there is no delete dialog-call...
Also, not passing this seems to be intentional:
[The FindDialog's] constructor is defined to accept a parent QWidget, even though the dialog will be opened as a separate window.
Wouldn't this cause a memory leak? Or is there some other mechanism that will silently delete dialog and free its memory?
Thanks in advance for any help!
Update: I posted this issue to the qt-project.org forums and it should get fixed soon.
There is no excuse for this, and it eventually has more issues than you just bring up, namely:
It is not managed as you say.
It does not use the conventional new Foo() syntax.
It is not done in the constructor's initializer list.
The OS will probably free this up once the application quits, but still, I always speak up against such issues, anyhow, especially in example projects. The appropriate fix would be to use either a stack object instead of the heap object or QPointer in my opinion.
See the following post for details in case the latter:
How to crash (almost) every Qt/KDE Application and how to fix
This should be reported and fixed upstream; good catch!
I have just submitted a change to Gerrit about this in here.
So, I think I've searched the web quite thoroughly about this and found nothing really useful (just confusing at most...).
I'd like to know how I can (if possible) use Qt with non-dynamic memory. The problem I face is that for many widgets, I know exactly what I want to use (these sub-widgets, these layouts, in fixed numbers, etc.). Yet, everything in Qt seems to get in the way when you don't use dynamic memory. A simple example is QLayout, which from the Qt documentation is designed to take ownership of anything it is added. So basically, the following code:
//In header
class ThumbnailDialog : public QDialog
{
Q_OBJECT
public:
ThumbnailDialog(QWidget* parent = 0);
~ThumbnailDialog(void);
private:
QPushButton m_confirm;
QPushButton m_cancel;
QHBoxLayout m_buttonsLayout;
};
//Implementation of ctor
ThumbnailDialog::ThumbnailDialog(QWidget* parent):
QDialog(parent)
{
//...
m_buttonsLayout.addWidget(&m_confirm);
m_buttonsLayout.addWidget(&m_cancel);
//...
setLayout(&m_dialogLayout);
}
...will end up (on MSVC) in a debug assertion fail for _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) because, in the ThumbnailDialog's dtor, the layout tries to delete the buttons... which it obviously shouldn't.
So, am I forced to use dynamic memories everywhere, as this "Qt Expert" advocates (while mentioning "heap", though...) ? This seems wrong as this prevents taking advantage of RAII (if parent-child relation means there'll be a delete, one can't use smart pointers to do that I suppose, then). It also feels terribly wrong to resort to dynamic memory for things known at compile-time... (but I could be wrong, that's just my feeling).
So: is there any way of using Qt without resorting to dynamic memory and news for every single widget/layout ?
I think you are misunderstanding the problem here. You are not double deleting something, you are deleting an object allocated on the stack:
int foo = 12345;
int* pFoo = &foo;
delete pFoo;
This is what happens when you pass a pointer to a stack based object to QHBoxLayout, hence your heap corruption debug assert.
Qt manages QObjects this way because most GUI's have LOTS of widgets, which makes managing GUI object life times easier, it also allows queued deletes across threads etc. Also internally most classes use PIMPL's so you are not avoiding the heap/dynamic allocation even if your code worked.
Having said all this you can get it to work without the heap alloc if you wish, but it is far more effort than its worth. In your example you would have to remove the widgets from the layout in the destructor, but be sure the nullptr check things in case the ctor has thrown, if they're not in the layout when its destructor is hit then it won't be able to delete them.
One more thing to think about.. if Qt was designed to work this way then you could easily end up in the situation where you overflow the stack on some platforms. E.g Qt works on Symbian/S60 which has extremely limited stack, running your code there could easily cause a stackoverflow :).
Yes, there is. (and in a pretty clean way, I believe)
You just have to be aware about the order of destruction of your QObject hierarchy:
As explained in the Qt docs, a lot of objects claim ownership of their children and therefore want to make sure they get cleaned up when they die.
QObject’s dtor relieves its parent of that ownership.
Destruction of non-static data members happens from bottom to top.
Which means that, in your case, you just have to move the layout to the top:
private:
QHBoxLayout m_buttonsLayout;
QPushButton m_confirm;
QPushButton m_cancel;
All the layout’s children’s dtors unregister themselves from the layout, so when the layout destruction happens there are no registered childs left.
Previously the layout’s destruction deleted the children which where not newd in the first place.
This may seem tedious at first sight, but in practice the hierarchy within a custom widget is pretty flat. The order of widgets in one layer of the hierarchy – in this case the QPushButtons – is not important which usually means that you only have to arrange the layouts on top properly.
The problem you're seeing is that you're not thinking about what is happening. The QPushButton instances in the class are created and owned by the class. When the class is deleted, it will call the destructor on the QPushButtons.
Qt provides useful parenting of objects and deleting a parent will handle deletion of all its child objects.
So, in the case of your example, you have two things that are going to call the destructor on the QPushButtons: 1) The deletion of the class object for ThumbnailDialog and 2) The deletion of the buttonlayout, which will try to delete its children and will fail, as the object is on the stack.
What you can do, if you really want, is ensure that the QPushButton items are removed from the button layout, in the destructor of ThumbnailDialog by calling removeWidget() on the button layout.
However, this is messy. Dynamic allocation is a much better method, as it allocates objects on the heap and not the stack.
Also note, with Qt's parenting, it means that you can create a lot of widgets without needing to keep track of them. For example, you can do this: -
ThumbnailDialog::ThumbnailDialog(QWidget* parent):
QDialog(parent)
{
//...
m_buttonsLayout.addWidget(new QPushButton("Confirm"));
m_buttonsLayout.addWidget(new QPushButton("Cancel"));
//...
setLayout(&m_dialogLayout);
}
In this case, the push buttons don't even need to be defined in the header and you can be assured that they'll be deleted along with their parent.
No, not really. I'm afraid. Qt relies on this stuff.
If you have read the other answers and you still want to use static allocation, you can release the ownership that was taken when doing addWidget():
//...
m_buttonsLayout.addWidget(&m_confirm);
m_buttonsLayout.addWidget(&m_cancel);
// release the ownership by setting no parent
m_confirm.setParent(0);
m_cancel.setParent(0);
//...
this is probably a noob COM question, but googling this raises more questions than providing answers:
Is it safe to use "operator new" instead of CoCreateInstance for a local COM instance?
What I've done:
I implemented the IOperationsProgressDialog interface
http://msdn.microsoft.com/en-us/library/windows/desktop/bb775368(v=vs.85).aspx
by using public inheritence and thereby also implemented the IUnknown interface.
I created an instance via "new RecyclerProgressCallback" and put it into a COM-Ptr for life-time management. "RecyclerProgressCallback" is the name of my derived class.
I'm using this instance in IFileOperation::SetProgressDialog
http://msdn.microsoft.com/en-us/library/windows/desktop/bb775803(v=vs.85).aspx
Summary: My approach "seems" to work, but I don't trust it, there's just too much disconcerting information around COM object creation to rely on the observable behavior only.
Are there any subtle risks, fallacies or other problems? Thanks!
I've even put them on the stack. Andrey's answer (now deleted) incorrectly suggested that it is unsafe, because you bypass COM reference counting. This is faulty reasoning. COM doesn't count references; it delegates the responsibility to you. You have to call delete, or free(), or whatever your language uses, after COM calls your Release method on its last interface. The important word is after. Not when, because you're not obliged to do so immediately.
Similarly, CoCreateInstance is a long detour because COM is language-neutral and doesn't know whether an object must be created with malloc or new. You do, so just bypass the whole COM logic.
It depends what exactly you are instantiating. When you are supposed to provide a COM pointer noone asks you whether it is instantiated with COM API, or new, or it can sometimes be even object on stack (provided that you manage to ensure it is not destroyed on stack before all references are released).
So the answer is yes, you can use new and it would be fine. However, it should be a valid COM interface anyway, it should implement reference counting and QueryInterface the way COM objects do.
CoCreateInstance API will look at the registry find the module that match specified CLSID, load it and the through a mechanism(it depend whether your code is DLL or EXE) it will call some functions to create your object. So for your code in order to make CoCreateInstance to work, you should write a class that implement IClassFactory interface of COM and register it in the registry and then call CoCreateInstance that do a couple of extra work with your code to at least do your lovely operator new, then yes of course it is safe. In general it is always safe to call operator new of implementation of source interfaces(interfaces that only declared for callback) in your code and this is also the preferred way.
This will work fine. This is how a COM server would typically create its objects internally (at least one written in C++). From your point of view, the RecyclerProgressCallback class is just some C++ code. You can treat it as any other class in your program.
That being said, COM is a minefield of subtle gotchas. I can't promise that you won't encounter problems with your class, but I can assure you that those problems will be unrelated to your use of operator new.
It's generally not safe, not just because of reference counting but also because of marshalling: the class may have a threading model that requires marshalling. CoCreateInstance will create a proxy and stub if that's the case, whereas new will not.
This resource describes a method of creating a modeless dialog using pointers. They create a pointer that pointer to the dialog class and then use the -> syntax.
CModeLess *m_pmodeless = new CModeLess(this);
m_pmodeless->Create(CModeLess::IDD);
m_pmodeless->ShowWindow(SW_SHOW);
I have been doing something like this so far:
CModeLess m_pmodeless;
m_pmodeless.Create(IDD_DIALOG);
m_pmodeless.ShowWindow(SW_SHOW);
I do this mainly because I feel comfortable using classes. Is there any disadvantage of using this approach?
Secondly, in the pointer approach I have to do something like this to close the window: (if I am not mistaken)
if(m_pmodeless != NULL) { delete m_pmodeless; }
Is there some deletion I have to do If I use classes or is m_pmodeless.closeWindow() enough?
I apologize if this is a very basic question, but i'm curious to know.
This is a tricky question to answer, as a lot depends on exactly what you are trying to do and also on exactly how CModeless is implemented. In general you are right to avoid pointers, but GUI programming has special issues because the C++ objects in your program represent GUI objects on the screen, and coordinating the destruction of the C++ objects in your program with the GUI objects on the screen can be quite tricky. Sometimes pointers are the simplest answer to this problem.
I'm assuming that m_pmodeless is a member variable of another class.
One issue is the lifetime of the objects. In the class version the CModeless object will be destroyed when the containing object is destroyed. Whether that's OK for you depends on your code. Whether that also destroys the modeless dialog depends on how CModeless is implemented. You need to look at the CModeless destructor if you can, or the documentation for CModeless if you can't. With the pointer version you have explicit control over when the object is destroyed, just call delete at the right time.
Another issue is that some GUI libraries automatically delete the C++ object when the GUI object is destroyed. Something like this (on Windows)
case WM_NCDESTROY:
...
// last message received so delete the object
delete this;
break;
Code like this is assuming that all your objects are heap allocated and automatically deleting them for you at the right time. If CModeless is written like this then you have no choice but to use the pointer version.
I've been looking for documentation for cocos2d-x but it seems to be really really poor beyond the very basics. I understand that my own classes should inherit from CCObject to be able to use (originally cocoa's) retain/release mechanism, but I'm still confused about what happens when you new something. init is not called automatically. is it OK to call it from inside the constructor? does that alone guarantee that my object will start with a reference count of 1? what is CC_SAFE_DELETE and when should I use it? do release and autorelease work exactly like in cocoa? what about CC_SYNTHESIZE? I just need to see a properly coded class example (and it's instantiation/destruction) to understand what I'm supposed to do so as not to screw and leave memory leaks.
thank you.
If you will look to the code of CCObject class, you will see that in it's constructor reference count is set to 1 there. So, object creation with new is correct. Init is not called because CCObject class has no such a method. Usually I prefer to create objects using static constructor. Smth like
MyClass* MyClass::createInstance()
{
MyClass* object = new MyClass();
// you can create virtual init method
// and call it here
if( initWasSuccessful )
{
object->autorelease();
}
else
{
CC_SAFE_RELEASE_NULL(object);
}
return object;
}
About all macroses like CC_SAFE_DELETE - you can find them in the code of cocos2dx. This macros just check if object is NULL to prevent crash on trying to call release method.
The answer provided by Morion is great, I'd just like to add a few useful links about this matter.
Here you can find the official memory management in Cocos2d-x page:
Memory Management in Cocos2d-x
This forum page also contains some more details and clarifications about it:
Memory deallocation in Cocos2d-x
Enjoy coding!