Member variables vs new?
-
I am using a control from the Qt repo called the QtPropertyBrowser. I subclassed the control to make it a bit simpler to use internally. This control has a concept where it uses "manager" to manage the properties and their values and "factories" which create the edit control when you click to change the value. Each manager needs to be connected to a factory. Because I'm making my subclass sort of generic I connected every possible combination of manager to factory and then simply add properties to the proper manager based on what is needed.
But I ran into a bit of a weird issue, which I think is more Qt related than specific to the control. Originally I just created all the managers and factories as member variables to my subclass and then pass those to the setFactoryForManager function using &m_memberVariableName in place of the pointer. But this created strange behavior. Most of the time it worked fine, but occasionally when control is created the setFactoryForManager function would fail and then none of the properties were editable. Internally it looked like it was comparing the manager and factory to some sort of reference list and deciding that the pair already existed. I changed all the member variables to pointers instead, and created them via "new" in the constructor, and the issue went away.
My question is... is this just how Qt is suppose to work? Are you always suppose to create QObjects on the heap rather than the stack? Is that why I was seeing this unpredictable behavior? Or is this some sort of design flaw in the QtPropertyBrowser control?
I've been a C++ developer for almost 20 years and typically try to avoid pointers whenever possible because a period is easier to type than -> and because then I don't have to worry about memory leaks. But Qt seems to use pointers for almost everything. And if this is any indication it actually "needs" pointers for everything.
-
Did not read the full story but never ever create a QObject on the stack when you give it a parent. Otherwise you may get into trouble when the parent is deleted earlier than the child since then an object on the stack gets deleted and you will get a crash.
-
@Christian-Ehrlicher said in Member variables vs new?:
Did not read the full story but never ever create a QObject on the stack when you give it a parent. Otherwise you may get into trouble when the parent is deleted earlier than the child since then an object on the stack gets deleted and you will get a crash.
I'm sorry, but I have a bone to pick with that advice, as usual. Creating
QObject
s on the stack is perfectly fine, also ones with parents as long as the objects are properly ordered, i.e. FILO (stack) ordering. A rule of thumb is that creating children with a parent set through the constructor is fine, whilesetParent
is evil in this case.@Dan203 said in Member variables vs new?:
My question is... is this just how Qt is suppose to work? Are you always suppose to create QObjects on the heap rather than the stack?
No, but you should observe ownership properly. Parents own their children, so whenever the parent goes out of scope it's going to try to clean up, if said children are on the stack they must've been automatically cleaned (their destructor deregisters them from the parent's list) before the parent's destructor runs. That's how it works basically.
-
@kshegunov the biggest issue is that some classes take ownership of objects when you pass them to one of their functions, which they then try to delete when they're destroyed. Some do not. It's not always clear when this is happening.
The specific issue I'm having here seems to be related to the "manager" taking ownership of the "factory" in this fashion. But I'm not 100% sure. All I know for sure is that switching to pointers somehow fixed the problem. The exact cause is still unclear.
-
@Dan203 said in Member variables vs new?:
@kshegunov the biggest issue is that some classes take ownership of objects when you pass them to one of their functions, which they then try to delete when they're destroyed. Some do not. It's not always clear when this is happening.
Yes, that's why you must be careful. The documentation indicates ownership transfer, which is almost always for widget based types. If that should happen the ownership acquiring object must outlive the transferred object for stack allocations to function properly. That's why you see so much heap allocations in fact, because it isn't always trivial or convenient to ensure the above.