QVariant from custom type unexpectedly crashes but always works under debugger
-
Hello to everybody!
I have my ModelObject derived from QObject, some custom types subclasses of ModelObject, some of them have properties as pointers to other custom classes. When I try to work with them as QVariant (using properties) them unexpectedly crashes. But I can't debug the problem because under debugger everything is 100% working!
ModelObject:
@
class ModelObject : public QObject
{
Q_OBJECT
Q_PROPERTY(qlonglong modelId READ modelId WRITE setModelId NOTIFY modelIdChanged)
...public:
void toXml(QXmlStreamWriter &writer) const;
}Q_DECLARE_METATYPE(ModelObject)
@I have two subclasses of my ModelObject -
StationType:
@
class StationType : public ModelObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
...
}Q_DECLARE_METATYPE(StationType)
@and Station:
@
class Station : public ModelObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
...
Q_PROPERTY(StationType *type READ type WRITE setType NOTIFY typeChanged)
...
}
Q_DECLARE_METATYPE(Station)
@And have following code in my toXml:
@
for (int i = 0; i < metaObject()->propertyCount(); i++) {
QString name = metaObject()->property(i).name();
QVariant value = property(name.toStdString().c_str());
// Program chrashes here, accessing value for property 'type':
qDebug() << name << "=>" << value;
}
@Program crashes when I call toXml() for Station, but all properties before type are printed ok!
How can I debug it and find the problem if under debugger all is working perfectly?
-
Hi,
The debugger is too kind for us sometimes. When initialize in debugger, all pointers, variables etc are set to zero! Even if you do not explicitly set so in the constructor. So, yes, in debugger most of the time all is well, but in the real application you get strange crashes. Then when the variables are not set to a default value some garbage left over in the memory is used, so with pointers it might be strange address ranges or even wrong addresses in the application program variables altering it with our you wanting to do so. Just make sure that every class/every variable and every function has all the variables initialize to default values. So even created pointers need to be set to NULL!!!! -
Ok, thank You. I'll check everything twice))
-
Hi,
There's also something else that is fishy here, how did you succeed building your code with these Q_DECLARE_METATYPE ? It's not possible with QObject derived classes.
-
First of all it seems I've found my problem, thanks to Jeroen! )))
After checking my code again I've found that I'm using QList<MyObject> property in object which is passed to QML code... Or may be it was not properly initialized... I'm not 100% sure, but after I commented this property out, my code started to work perfectly. I'll check it again later and rewrite it using QQmlListProperty.
And second... What is a problem to use Q_DECLARE_METATYPE with QObject derived class? I think this macro is used to register my QObject derived class for QVariant conversion system.
-
You can register a meta type with QObject * but not QObject. A meta type must provide a copy and assignment operator which are not available with QObject since copying a QObject is not possible.
-
Ok, Thank You for information, I'll check my code for this too.
-
Did you by any chance add these two functions in your derived class ?
-
Yes, You're absolutely right, I have copy constructor:
@
ModelObject::ModelObject(const ModelObject ©, QObject *parent) :
QObject(parent)
{
for (int i = 0; i < metaObject()->propertyCount(); i++) {
const char *name = metaObject()->property(i).name();
setProperty(name, copy.property(name));
}
}
@ -
But you're not able to properly copy a QObject instance. e.g. How is one child be able to have two parents? (you copy the parents with all children??). So that is why you should not copy a QObject. In your copy constructor you manual overwrite that QObject protection. And if you use a QObject derived class, then this is your base class and you do not need the Q_DECLARE_METATYPE!
-
Ok, Thanks. I understand the problem and will refactor my base class. I use QObject as base for my model objects because I want to use Qt property and signal/slot mechanism and never set parent explicitly. But of course if it's wrong it has to be rewritten)))
-
Hello!
I did some research and found that:
I want to make my model objects to support properties (because it's very useful - I can make some kind of introspection, universal serialization/deserialization of my model objects, property access from QML code and many-many things more...)
So I have to make them inherit QObject
I want to use them in Qt MetaType system and in QML
So I have to call qRegisterMetatype and qmlRegisterType
So I have to call Q_REGISTER_METATYPE macro in my model object header file
So I have to provide public copy constructor
What's wrong in my implementation? And how to make it more right way if You say that copy constructor of QObject derived class is wrong?
-
The no copy part is explained "here":http://qt-project.org/doc/qt-5/qobject.html#no-copy-constructor-or-assignment-operator
Use pointers
-
I'm sorry for foolish question)))
Assuming I have
@
class ModelObject: public QObject
{
...
}
// NO Q_DECLARE_METATYPE(ModelObject)
@Have I write:
@
qRegisterMetaType<ModelObject*>();
@and
@
qmlRegisterType<ModelObject*>();
@then it'll be possible to use my ModelObject with properties and from QML and I'll not have to provide wrong copy constructor?
-
When you want to bring something on the QML side you give pointers to QObject classes.