Qt 属性是否假定对象是指针而不是成员?
Do Qt properties assume objects are pointers and not members?
假设我有一个 C++ 对象,其中包含一个我向 QML 公开的成员对象:
class X : public QObject
{
Q_OBJECT
};
class Y : public QObject
{
Q_OBJECT
Q_PROPERTY(X* x READ getX CONSTANT)
public:
X* getX(void) { return &x; }
X x;
};
大多数情况下这是可行的,但有时会导致崩溃。调用堆栈很长但是是这样的:
QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData> >::data
qGetPtrHelper<QScopedPointer<QObjectData>>
QObject::d_func
QObjectPrivate::get
QQmlNotifierEndpoint::disconnect
QQmlNotifierEndpoint::~QQmlNotifierEndpoint
QQmlJavaScriptExpressionGuard::~QQmlJavaScriptExpressionGuard
QRecyclePool<QQmlJavaScriptExpressionGuard, 1024>::Delete
QQmlJavaScriptExpressionGuard::Delete
QQmlJavaScriptExpression::GuardCapture::captureProperty
QQmlEnginePrivate::captureProperty
QV4::QObjectWrapper::getProperty
etc.
如果我将 X
设置为指针:
class Y : public QObject
{
Q_OBJECT
Q_PROPERTY(X* x READ getX CONSTANT)
public:
Y()
{ x = new X; }
X* getX(void) { return x; }
X* x;
};
崩溃消失了。
这是 Q_PROPERTY
的已知限制吗,如果您 return 指向 QObject
的指针,则假定该对象是指针(不是成员)和其他东西像 deleteLater()
可能被称为?
发生此崩溃的最有可能是因为 QML 取得了对象 c
您的函数 returns 的所有权,并希望稍后将其删除。
在您的第一个示例中,由于 x
不是从免费商店分配的,因此尝试删除它会崩溃。
在第二个示例中,QML 引擎仍然尝试删除它,但没有问题。
要问的问题是,为什么 QML 引擎会取得对象的所有权?
Data Type Conversion Between QML and C++ | Data Ownership 中的文档说明:
When data is transferred from C++ to QML, the ownership of the data always remains with C++. The exception to this rule is when a QObject is returned from an explicit C++ method call: in this case, the QML engine assumes ownership of the object, unless the ownership of the object has explicitly been set to remain with C++ by invoking QQmlEngine::setObjectOwnership() with QQmlEngine::CppOwnership specified.
Additionally, the QML engine respects the normal QObject parent ownership semantics of Qt C++ objects, and will not ever take ownership of a QObject instance which already has a parent.
因此,为了解决您的问题,您可以影响 x
对象的 QObject
父对象,或者明确声明它具有 QmlEngine::CppOwnership
.
假设我有一个 C++ 对象,其中包含一个我向 QML 公开的成员对象:
class X : public QObject
{
Q_OBJECT
};
class Y : public QObject
{
Q_OBJECT
Q_PROPERTY(X* x READ getX CONSTANT)
public:
X* getX(void) { return &x; }
X x;
};
大多数情况下这是可行的,但有时会导致崩溃。调用堆栈很长但是是这样的:
QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData> >::data
qGetPtrHelper<QScopedPointer<QObjectData>>
QObject::d_func
QObjectPrivate::get
QQmlNotifierEndpoint::disconnect
QQmlNotifierEndpoint::~QQmlNotifierEndpoint
QQmlJavaScriptExpressionGuard::~QQmlJavaScriptExpressionGuard
QRecyclePool<QQmlJavaScriptExpressionGuard, 1024>::Delete
QQmlJavaScriptExpressionGuard::Delete
QQmlJavaScriptExpression::GuardCapture::captureProperty
QQmlEnginePrivate::captureProperty
QV4::QObjectWrapper::getProperty
etc.
如果我将 X
设置为指针:
class Y : public QObject
{
Q_OBJECT
Q_PROPERTY(X* x READ getX CONSTANT)
public:
Y()
{ x = new X; }
X* getX(void) { return x; }
X* x;
};
崩溃消失了。
这是 Q_PROPERTY
的已知限制吗,如果您 return 指向 QObject
的指针,则假定该对象是指针(不是成员)和其他东西像 deleteLater()
可能被称为?
发生此崩溃的最有可能是因为 QML 取得了对象 c
您的函数 returns 的所有权,并希望稍后将其删除。
在您的第一个示例中,由于 x
不是从免费商店分配的,因此尝试删除它会崩溃。
在第二个示例中,QML 引擎仍然尝试删除它,但没有问题。
要问的问题是,为什么 QML 引擎会取得对象的所有权? Data Type Conversion Between QML and C++ | Data Ownership 中的文档说明:
When data is transferred from C++ to QML, the ownership of the data always remains with C++. The exception to this rule is when a QObject is returned from an explicit C++ method call: in this case, the QML engine assumes ownership of the object, unless the ownership of the object has explicitly been set to remain with C++ by invoking QQmlEngine::setObjectOwnership() with QQmlEngine::CppOwnership specified.
Additionally, the QML engine respects the normal QObject parent ownership semantics of Qt C++ objects, and will not ever take ownership of a QObject instance which already has a parent.
因此,为了解决您的问题,您可以影响 x
对象的 QObject
父对象,或者明确声明它具有 QmlEngine::CppOwnership
.