【问题标题】:Qt disconnectNotify() not called on receiver object destructionQt disconnectNotify() 未在接收器对象销毁时调用
【发布时间】:2012-03-05 10:21:00
【问题描述】:

我有一个发出信号 S 的 C 类。S 可能连接到零、一个或多个接收器 (R)(连接数随时间变化,连接 w 由接收器进行)。

C 需要在 S 上的侦听器数量大于零时执行操作,并在 S 上的侦听器数量恢复为零时执行其他操作。

我认为我可以使用:

connectNotify()

disconnectNotify()

嗯……

我注意到 connectNotify() 函数运行良好,但是当接收对象被销毁时,disconnectNotify() 没有被调用(在 C 类中)。仅当使用 disconnect() 显式断开连接时才会调用它。

在侦听器的析构函数中添加显式断开连接也不是很成功:退出整个应用程序时出现分段错误。 (我想在一切都不好的时候尝试使用 disconnect() 并不是很好。)

当 R 被销毁时,我尝试使用从 R 实例发送到 C 的 destroy() 信号:这可行,但我如何确定 R 在销毁时已连接? (接收者R可能处于非连接状态):

在 C 类中,插槽 X(在接收 R 的destroy() 时调用),检查 QObject::receivers(),似乎返回执行销毁之前的接收者数量。由于我不知道被破坏的对象是否已连接,所以我被卡住了!

有什么想法吗?

【问题讨论】:

  • 我在测试应用程序中得到了相同的行为;这似乎与我的文档不一致。您在析构函数中显式断开连接的想法对我有用,但是程序中的破坏顺序可能会搞砸。我很想知道当信号的接收器被破坏时是否还有其他人可以得到disconnectNotify
  • 这已在 Qt 5 中修复。请参阅 QTBUG-4844

标签: c++ qt


【解决方案1】:

如果你能确保所有的 R 在 C 之前被销毁,你可以在 C 类中自己管理连接:

头文件:

#include <QtCore/QSet>

class C : (...)
{
    (...)

public:
    void connectReceiver( QObject* receiver );

private slots:
    void handleReceiverDestruction( QObject* receiver );

private:
    QSet< QObject* > _connectedReceivers;
};

源文件:

void C::connectReceiver( QObject* receiver  )
{
    // nothing to do if the receiver is already connected
    if( _connectedReceivers.contains( receiver  ) ) return;

    _connectedReceivers.append( receiver )

    connect( ... ); // <- do your connection(s) here
    connect( receiver, SIGNAL( destroyed                ( QObject* ) ), 
             this    , SLOT  ( handleReceiverDestruction( QObject* ) ) );
}

void C::handleReceiverDestruction( QObject* receiver )
{
    if( !_connectedReceivers.contains( receiver ) )
    {
        // if this happens, a receiver R's destroyed() signal was connected to
        // this function altough R is not a receiver of signal X.
        Q_ASSERT( false );
        return;
    }

    disconnect( ... ); // <- one or more might be necessary here

    _connectedReceivers.remove( receiver );
}

提示:我没有测试编译或逻辑错误,但你应该明白了。

就个人而言,我可能会添加以下内容:

C::~C()
{
    if( !_connectedReceivers.isEmpty() )
    {
        // If you land here, a receiver was not (properly) destroyed before this object
        Q_ASSERT( false );
    }
}

【讨论】:

  • 谢谢,这与我尝试做的解决方法非常接近。我还会不时检查 QOBject::receivers(),因为当接收器被销毁时 QObject::receivers() 似乎会减少(但这发生在接收到 C 中的 destroy() 信号之后)。它们是许多可能的解决方法,但我仍然觉得 disconnectNotify 的行为很奇怪,再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-03
  • 2014-01-02
  • 2022-11-28
  • 2014-08-28
  • 1970-01-01
相关资源
最近更新 更多