При соединении с указателями, которые находятся внутри локального map
, вылетает программа с ошибкой: Segmentation fault
. Если сделаю мап статик или как поле, то все будет работать.
Вопрос: почему ломается коннект, если map
хранит указатели на объекты, а не сами объекты? Какие решение есть, кроме как статик?
Вот пример, который смог сделать:
someobj.h
#ifndef SOMEOBJ_H
#define SOMEOBJ_H
#include <QObject>
#include <QDebug>
class SomeObj : public QObject
{
Q_OBJECT
public:
explicit SomeObj(QObject *parent = nullptr) : QObject(parent) { }
public slots:
void someSlot() { qDebug() << "someSlot"; }
};
#endif // SOMEOBJ_H
mainwindows.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "someobj.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
SomeObj obj[7];
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QMap<QPushButton *, SomeObj *> m {
{ ui->pushButton, &obj[0] },
{ ui->pushButton_2, &obj[1] },
{ ui->pushButton_3, &obj[2] },
{ ui->pushButton_4, &obj[3] },
{ ui->pushButton_5, &obj[4] },
{ ui->pushButton_6, &obj[5] },
{ ui->pushButton_7, &obj[6] }
};
for (auto it = m.begin(); it != m.end(); ++it) {
connect( it.key(), &QPushButton::clicked, [=] () {
it.value()->someSlot();
qDebug() << it.key()->objectName();
ui->btnStop->setEnabled(true);
});
}
}
MainWindow::~MainWindow()
{
delete ui;
}
UPD1: а почему нельзя вызвать sender()
в анонимной функции?
UPD2: При раскомменчивании любой строчки программа вылетает.
for (auto it = m.begin(); it != m.end(); ++it) {
connect( it.key(), &QPushButton::clicked, [=, obj = it.value(), btn = it.key()] () {
// obj->someSlot(); // #1
// qDebug() << sender()->objectName(); // #2
qDebug() << obj->objectName(); // работает
qDebug() << btn->objectName(); // работает
ui->btnStop->setEnabled(true);
});
}
UPD3: При попытке:
connect( it.key(), &QPushButton::clicked, [obj = it.value(), btn = it.key(), ui] () {...
вылетает ошибка 'ui' in capture list does not name a variable
. Поэтому так:
connect( it.key(), &QPushButton::clicked, [obj = it.value(), btn = it.key(), uii = ui] () {
// obj->someSlot(); // #1
// qDebug() << sender()->objectName(); // #2
qDebug() << obj->objectName(); // работает
qDebug() << btn->objectName(); // работает
uii->btnStop->setEnabled(true);
});
И так, уже функция sender() не видна, тк this не передается. Но почему при раскомменчивании #1
программа вылетает?
UPD4: все договариваю. Могу проект скинуть. Класс SomeObj
не изменял.Конструктор MainWindow изменил так:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QMap<QPushButton *, SomeObj *> m {
{ ui->pushButton, &obj[0] },
{ ui->pushButton_2, &obj[1] },
{ ui->pushButton_3, &obj[2] },
{ ui->pushButton_4, &obj[3] },
{ ui->pushButton_5, &obj[4] },
{ ui->pushButton_6, &obj[5] },
{ ui->pushButton_7, &obj[6] }
};
for (auto it = m.begin(); it != m.end(); ++it) {
connect( it.key(), &QPushButton::clicked, [obj = it.value(), btn = it.key(), btnS = this->ui->btnStop] () {
// obj->someSlot(); // #1
// qDebug() << sender()->objectName(); // #2
qDebug() << obj->objectName(); // работает
qDebug() << btn->objectName(); // работает
btnS->setEnabled(true);
});
}
}
"Теоретически" ваш map
хранит указатели на интересующие вас объекты и в правильно написанном коде время жизни самого map
не должно влиять на работоспособность вашего кода. Однако вы написали вашу лямбда-функцию так, что она занимается захватом итераторов этого map
и всю работу делает через эти итераторы. В такой ситуации, как только map
прекращает свое существование, попытки доступа через её итераторы приводят к падению программы.
Прекратите захватывать итераторы и перепишите свою лямбду так, чтобы она захватывала значения указателей it.key()
и it.value()
и далее работала именно через захваченные указатели, а не через итератор. Таким образом вы полностью отвяжете вашу лямбду от этого временного map
[=, obj = it.key(), button = it.value()] ()
{
obj->someSlot();
qDebug() << button->objectName();
ui->btnStop->setEnabled(true);
}
Более того, при создании долгоживущих лямбд я бы посоветовал вам не пользоваться механизмом неявного захвата. Лучше прописывайте все захваты явно, чтобы отдавать себе отчет в том, что именно вы захватываете и к каким последствиям это может привести
[obj = it.key(), button = it.value(), ui = this->ui] ()
{
obj->someSlot();
qDebug() << button->objectName();
ui->btnStop->setEnabled(true);
}
Виртуальный выделенный сервер (VDS) становится отличным выбором
В юнит-тестах на java+spring передаю в метод строку с русскими буквамиВнутри метода в параметр приходит уже не то, что записал, например статус...
Создаю 2д стрелялку на LibgdxЕсть спрайт космического корабля и снаряда
О том как работает HashMap в принципе все понятноЧто такое бандлы, сложность поиска и тд
Как создавать кастомные элементы Preference Framework? Например, ввод целых или вещественных чисел с такой своеобразной "прокруткой", или например...