在 QObject 派生类的构造函数中使用 deleteLater

Posted

技术标签:

【中文标题】在 QObject 派生类的构造函数中使用 deleteLater【英文标题】:Using deleteLater into constructor of QObject-derived class 【发布时间】:2018-01-24 19:00:50 【问题描述】:

Example code is here.

我在导出到 QML 的 C++ 对象中发现了一个类似于指针类型属性的习惯用法。由于外部事件的发生,这些属性的指针可以随时停止存在。为此,我使用QObject::deleteLater 插槽。 <property>Changed 信号(QML 需要)可以连接到QObject::destroyed 信号。我注意到在发出这个信号的那一刻QPointer 已经很清楚了。所以属性值将在正确的时刻在 QML 端有效。

查看QPointer 标头我注意到它基于QWeakPointer/QSharedPointer 并且似乎使用过的行为(即“QPointer 在调用连接到destroyed 信号的第一个插槽之前变得清晰”)不知何故硬设置,但未在文档中指定。

在我的例子中,属性是指向 QDBusAbstractInterface 派生类 [1] 的指针,它对应于 NetworkManager D-Bus 服务接口。 NetworkManager D-Bus 服务可能会意外取消注册,并且上述所有类都无法使用,并且每个类的 QDBusAbstractInterface::isValid() 都变为 false

QDBusAbstractInterface 派生类创建后的生命周期内,我可以通过 QDBusServiceWatcher 观察者来管理这种情况。

但在创建QDBusAbstractInterface-派生类期间,我不能依赖服务可用性。即使我通过QDBusConnection::systemBus().interface()->isServiceRegistered(QStringLiteral(NM_DBUS_SERVICE)) 检查服务的可用性,它也可能在下一个运算符之前立即变得不可用(就 C++ 而言)。因此,在构造其 QDBusAbstractInterface 基础之后,构造的类可能无法使用(即 QDBusAbstractInterface::isValid()false)。

我目前所做的是根据isValid()deleteLater() [2] 调用到构造函数中。在我看来,一旦到达事件循环,这最终会导致对象在其构造后立即销毁。

是否允许在QObject派生类的构造函数中调用deleteLater()槽?

【问题讨论】:

【参考方案1】:

是否允许在构造函数中调用 deleteLater() 槽 QObject 派生类?

这只是处理无效对象的不寻常且不明显(类消费者可能不希望这样做)的方式,我们总是可以在使用类工厂模式创建类实例之前检测类的实例是否无效:

class MyNetworkManager

public:
   // static create method
   static MyNetworkManager* create();

private:
   // private constructor
   MyNetworkManager();
;

/*static*/ MyNetworkManager* MyNetworkManager::create()

   // This method may contain all the necessary logic
   // to avoid producing an invalid class instance.
   if (nwkSystem.isReady())
       retrun new MyNetworkManager;

   return nullptr;


// usage would be
auto* p = MyNetworkManager::create();
if (!p)

    qDebug() << "the system is not ready for MyNetworkManager";

【讨论】:

看来你没看清楚这个问题。在您执行nwkSystem.isReady()new MyNetworkManager 之间的答案中,前一个可以变成false。我特别指出了这一点。 @Orient,答案当然很简单,但您可以确保代码与构造函数中的方式相同,但在构造函数中不同。我看了你的代码, ... 如果类的实例在其生命周期内变得无效,则可以将信号发送给类的消费者,然后 deleteLater() 将是一些隐含的误导行为。跨度> 我同意。似乎最好在构造后立即检查isValid() 并将delete 应用于原始指针。 ...并且在此检查之前不通过setProperty 分配新值。

以上是关于在 QObject 派生类的构造函数中使用 deleteLater的主要内容,如果未能解决你的问题,请参考以下文章

Python类与对象最全总结大全(类实例属性方法继承派生多态内建函数)

派生类的构造函数与析构函数的调用顺序

C++基类和派生类的构造函数

调用派生类的构造函数在基类的构造函数之前执行

在派生类的构造函数中初始化没有默认构造函数的基类

在其派生类C++的构造函数中调用基类的构造函数[重复]