- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我需要帮助了解 lambda 函数的工作方式,以防止在使用它们时发生内存泄漏。更具体地说,我想知道在以下情况下 foo
何时会被销毁:
void MainWindow::onButtonClicked()
{
QTimer *t(new QTimer(this));
bool foo = false;
t->setSingleShot(true);
t->setInterval(1000);
t->start();
connect(t, &QTimer::timeout, [=](){
delete t;
qDebug() << foo;
});
}
使用[&]
的情况呢?
最佳答案
一个求值的 lambda 表达式是一个仿函数实例。仿函数是一个带有 operator()
的对象。捕获的变量是该仿函数对象的成员。 它们的生命周期不会根据它们的类型而改变。因此,无论您捕获引用还是值,它们的生命周期都是相同的。 您的工作是确保引用有效 - 即它们引用的对象没有被破坏。
仿函数的生命周期与连接的生命周期相同。连接以及仿函数将持续到:
QObject::disconnect()
在 QObject::connect()
的返回值上被调用,或者
QObject
的生命结束,它的析构函数被调用。
考虑到上述情况,局部变量引用捕获的唯一有效用途是局部变量比连接更长的时间。一些有效的例子是:
void test1() {
int a = 5;
QObject b;
QObject:connect(&b, &QObject::destroyed, [&a]{ qDebug() << a; });
// a outlives the connection - per C++ semantics `b` is destroyed before `a`
}
或者:
int main(int argc, char **argv) {
QObject * focusObject = {};
QApplication app(argc, argv);
QObject * connect(&app, &QGuiApplication::focusObjectChanged,
[&](QObject * obj){ focusObject = obj; });
//...
return app.exec(); // focusObject outlives the connection too
}
您问题中的代码不必要地复杂。无需手动管理此类计时器:
void MainWindow::onButtonClicked() {
bool foo = {};
QTimer::singleShot(1000, this, [this, foo]{ qDebug() << foo; });
}
这里的重要部分是提供对象上下文 (this
) 作为 singleShot
的第二个参数。这确保了 this
必须比仿函数活得更久。相反,仿函数将在 this
被销毁之前被销毁。
假设您真的想实例化一个新的 transient 计时器,删除连接到此类信号的槽中信号的源对象是未定义的行为。您必须将删除推迟到事件循环:
void MainWindow::onButtonClicked()
{
auto t = new QTimer(this);
bool foo = {};
t->setSingleShot(true);
t->setInterval(1000);
t->start();
connect(t, &QTimer::timeout, [=](){
qDebug() << foo;
t->deleteLater();
});
}
t
和foo
都被复制到仿函数对象中。 lambda 表达式是一种符号速记 - 您可以自己明确地编写它:
class $OpaqueType {
QTimer * const t;
bool const foo;
public:
$OpaqueType(QTimer * t, bool foo) :
t(t), foo(foo) {}
void operator()() {
qDebug() << foo;
t->deleteLater();
}
};
void MainWindow::onButtonClicked() {
//...
connect(t, &QTimer::timeout, $OpaqueType(t, foo));
}
由于 lambda 实例只是一个对象,如果多个信号需要连接到同一个 lambda,您当然可以将它分配给一个变量并消除代码重复:
auto f = [&]{ /* code */ };
connect(o, &Class::signal1, this, f);
connect(p, &Class::signal2, this, f);
lambda 的类型是唯一的、不可言说的,也称为不透明类型。你不能从字面上提及它——语言中没有这样做的机制。您只能通过 decltype
引用它。这里的 decltype
是 he who shall not be named 中的 he。 C++ 的人只是在哈利波特的笑话中工作,不管他们是否有意。否则我不会相信。
关于c++ - 在用作槽的 lambda 函数中捕获的堆栈分配变量的生命周期是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45644334/
我正在开发一个使用多个 turtle 的滚动游戏。玩家 turtle 根据按键命令在 Y 轴上移动。当危害和好处在 X 轴上移动时,然后循环并改变 Y 轴位置。我尝试定义一个名为 colliding(
我不明白为什么他们不接受这个作为解决方案,他们说这是一个错误的答案:- #include int main(void) { int val=0; printf("Input:- \n
我正在使用基于表单的身份验证。 我有一个注销链接,如下所示: 以及对应的注销方法: public String logout() { FacesContext.getCurren
在 IIS7 应用程序池中有一个设置 Idle-time out 默认是 20 分钟,其中说: Amount of time(in minutes) a worker process will rem
我是一名优秀的程序员,十分优秀!