gpt4 book ai didi

c++ - 第一次通话后断开插槽的优雅方式

转载 作者:可可西里 更新时间:2023-11-01 17:40:22 24 4
gpt4 key购买 nike

在构造器内部,有一个连接:

connect(&amskspace::on_board_computer_model::self(),
SIGNAL(camera_status_changed(const amskspace::camera_status_t&)),
this,
SLOT(set_camera_status(const amskspace::camera_status_t&)));

方法:

void camera_model::
set_camera_status(const amskspace::camera_status_t& status) {
disconnect(&amskspace::on_board_computer_model::self(),
SIGNAL(camera_status_changed(const amskspace::camera_status_t&)),
this,
SLOT(set_camera_status(const amskspace::camera_status_t&)));

// do the job
}

我想在第一次通话后断开这个插槽。

问题是:有没有办法只调用一次插槽?没有明确的断开连接?像单发方法?可能吗?

最佳答案

核心思想是创建一个包装器,一个自动断开信号的特殊“连接”。如果您使用很多“给我打电话一次”连接,这将很有用;否则我建议在插槽的开头使用 Qobject::disconnect。

此实现通过创建 2 个连接来工作:一个“正常”连接,一个会断开连接并立即清理所有连接。

一个实现(使用 C++11/Qt 5,):

template <typename Func1, typename Func2>
static inline QMetaObject::Connection weakConnect(
typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot)
{

QMetaObject::Connection conn_normal = QObject::connect(sender, signal, receiver, slot);

QMetaObject::Connection* conn_delete = new QMetaObject::Connection();

*conn_delete = QObject::connect(sender, signal, [conn_normal, conn_delete](){
QObject::disconnect(conn_normal);
QObject::disconnect(*conn_delete);
delete conn_delete;
});
return conn_normal;
}

注意事项/需要改进的地方:

  • 清理发生在调用常规插槽之后。如果常规插槽导致信号再次发射,则常规插槽将再次执行(可能导致无限递归)。
  • 没有正确的断开方式,除非发出信号。 (您可以使用 QObject::disconnect,但这会导致小的内存泄漏)
  • 依赖于槽的执行顺序。目前看来还好。
  • 命名

测试使用:

class A : public QObject
{
Q_OBJECT
signals:
void sig(int a);
};


class B : public QObject
{
Q_OBJECT
public:
B(int b) : QObject(), b_(b) {}
int b() const { return b_; }
public slots:
void slo(int a) { qDebug() << "\tB :" << b_ << "a:" << a; }
private:
int b_;
};

A a1;
A a2;

B b10(10);
B b20(20);

weakConnect(&a1, &A::sig, &b10, &B::slo);
weakConnect(&a1, &A::sig, &b20, &B::slo);
weakConnect(&a2, &A::sig, &b20, &B::slo);

qDebug() << "a1 :"; emit a1.sig(1);// Should trigger b10 and b20 slo
qDebug() << "a2 :"; emit a2.sig(2);// Should trigger b20 slo
qDebug() << "a1 :"; emit a1.sig(3);// Should do nothing
qDebug() << "a2 :"; emit a2.sig(4);// Should do nothing

测试代码输出:

a1 :
B : 10 a: 1
B : 20 a: 1
a2 :
B : 20 a: 2
a1 :
a2 :

摆脱 C++11/Qt5(我没有 Qt 4.8/GCC4.4.7,所以没有用它们进行测试)根据文档,Qt 4.8 没有连接功能,所以我使用包装器:

class ConnectJanitor : public QObject
{
Q_OBJECT
public slots:
void cleanup()
{
QObject::disconnect(conn_normal_);
QObject::disconnect(*conn_delete_);
delete conn_delete_;
delete this;
}
public:
static ConnectJanitor* make(QMetaObject::Connection conn_normal,
QMetaObject::Connection* conn_delete)
{
return new ConnectJanitor(conn_normal, conn_delete);
}
private:
ConnectJanitor(QMetaObject::Connection conn_normal,
QMetaObject::Connection* conn_delete) :
QObject(0) , conn_normal_(conn_normal), conn_delete_(conn_delete) {}

ConnectJanitor(const ConnectJanitor&); // not implemented
ConnectJanitor& operator=(ConnectJanitor const&);


QMetaObject::Connection conn_normal_;
QMetaObject::Connection* conn_delete_;
};

(我将 ConnectJanitor 的构造函数设为私有(private),因为该实例会自毁(删除此))

对于weakConnect:

static inline QMetaObject::Connection weakConnect(const QObject * sender, const char * signal, const QObject * receiver, const char * slot)
{
QMetaObject::Connection conn_normal = QObject::connect(sender, signal, receiver, slot);
QMetaObject::Connection* conn_delete = new QMetaObject::Connection();
*conn_delete = QObject::connect(sender, signal, ConnectJanitor::make(conn_normal, conn_delete), SLOT(cleanup()));
return conn_normal;
}

如果您需要手动断开连接,我建议让 weakConnect() 返回 ConnectJanitor 的指针。

关于c++ - 第一次通话后断开插槽的优雅方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27019290/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com