При соединении с указателями, которые находятся внутри локального 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);
}
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости