Название: Приложение падает при emit в пользовательском классе.
Отправлено: Arceny от Июнь 02, 2008, 19:08
Есть приложение, есть свой собственный класс sql на основе QObject. В конструкторе приложения инициализируется как db = new sql(this); При генерации сигнала из класса emit сигнал получаю ошибку сегментации. Этот сигнал пока ещё ни к чему не подключен. where #0 QMetaObject::activate (sender=0x0, m=0x806c208, local_signal_index=1, argv=0x0) at kernel/qobject.cpp:3076 #1 0x08069109 in sql::readCategories () #2 0x08066d9f in sql::deleteDisc () #3 0x0805f2d7 in myTree::deleteDisc () #4 0x08068c6d in myTree::qt_metacall () ...
Видно что валится при вызове из функции класса. Далее привожу весь код класса на всякий случай. Помогите, пожалуйста, найти ошибку. C++ (Qt) #ifndef SQL_H #define SQL_H #include <QObject> #include <QtSql> struct configuration; class sql : public QObject { Q_OBJECT public: sql(QObject *parent = 0); ~sql(); bool isOpen(); signals: void updateCategory(int catid); void readCategories(); private: QSqlDatabase db; configuration * cnf; bool checkQuery(QSqlQuery q); public slots: bool initDatabase(); bool openDatabase(); bool closeDatabase(); bool deleteDisc(int discid); bool deleteCategory(int catid); bool moveDisc(int discid, int oldid, int catid); bool moveAllDiscs(int oldid, int catid); bool addDisc(QString name, QString descr, int year, int catid); //bool addDisc(); }; #endif
C++ (Qt) #include <QMessageBox> #include "sql.h" #include "mainwindow.h" /// Класс, в который вынесен основной функционал работы с БД sql::sql(QObject *parent) : QObject(parent) { cnf = &((mainWindow*)parent)->cnf; } sql::~sql() { } // проверяет запрос на безошибочность bool sql::checkQuery(QSqlQuery q) { if ( q.lastError().type() != QSqlError::NoError ) { QMessageBox::critical(0,QCoreApplication::applicationName(),"SQL: "+q.lastQuery()+"\nError: "+q.lastError().text()); return false; } return true; } bool sql::initDatabase() { qDebug() << "sql::initDatabase()"; if(cnf->dbType=="QSQLITE") { QFile file(cnf->dbName); file.remove(); } if(openDatabase()) { QSqlQuery query; query.exec("CREATE TABLE category (" "id INTEGER PRIMARY KEY," "name VARCHAR(64) NOT NULL," "nth INTEGER NOT NULL," "items INTEGER)"); if(!checkQuery(query)) return false; query.exec("CREATE TABLE disc (" "id INTEGER PRIMARY KEY," "name VARCHAR(128) NOT NULL," "descr TEXT," "year INTEGER," "catid INTEGER NOT NULL," "FOREIGN KEY (catid) REFERENCES category)");// ON UPDATE CASCADE)"); if(!checkQuery(query)) return false; query.exec("CREATE TABLE files (" "id INTEGER PRIMARY KEY," // просто id записи "name VARCHAR(1024) NOT NULL," // имя файла/директории (не путь) "parentid INTEGER NOT NULL," // id записи родителя (директории), для верхнего уровня 0 "type INTEGER NOT NULL," // тип: директория или файл (тип файла по необходимости) "size INTEGER NOT NULL," // размер "date VARCHAR(20)," // дата файла, не обязательно "metadata INTEGER," // ссылка на метаданные если нужно. "discid INTEGER NOT NULL," // ссылка на диск к которому принадлежат файлы "FOREIGN KEY(discid) REFERENCES disc)"); if(!checkQuery(query)) return false; return true; } else return false; } bool sql::openDatabase() { qDebug() << "sql::openDatabase()"; closeDatabase(); db = QSqlDatabase::addDatabase(cnf->dbType); db.setDatabaseName(cnf->dbName); db.setHostName(cnf->server); db.setUserName(cnf->username); db.setPassword(cnf->password); if(!db.open()) { QMessageBox::warning(0, tr("Database error!"), db.lastError().text()); return false; } return true; } bool sql::closeDatabase() { qDebug() << "sql::closeDatabase()"; if(db.isOpen()) { QSqlQuery q1(db); q1.exec("VACUUM files"); q1.exec("VACUUM disc"); q1.exec("VACUUM category"); db.close(); QSqlDatabase::removeDatabase(db.connectionName()); // correct return true; } else return false; } bool sql::deleteDisc(int discid) { qDebug() << "sql::deleteDisc(int discid)"; QSqlQuery q; // извлекаем id категории q.prepare("SELECT catid FROM disc WHERE id = ?"); q.addBindValue(discid); q.exec(); q.next(); int catid = q.value(0).toInt(); // удаляем диск q.prepare("DELETE FROM disc WHERE id = ?"); q.addBindValue(discid); q.exec(); // удаляем файлы, принадлежащие диску q.prepare("DELETE FROM files WHERE discid = ?"); q.addBindValue(discid); q.exec(); // извлекаем число дисков из категории q.prepare("SELECT items FROM category WHERE id = ?"); q.addBindValue(catid); q.exec(); q.next(); int items = q.value(0).toInt(); // уменьшаем число дисков в категории на единичку q.prepare("UPDATE category SET items = ? WHERE id = ?"); q.addBindValue(items-1); q.addBindValue(catid); q.exec(); emit readCategories(); return true; } bool sql::moveAllDiscs(int oldid, int catid) { oldid=0; catid=0; return true; } bool sql::moveDisc(int discid, int oldid, int catid) { discid=0; oldid=0; catid=0; return true; } bool sql::deleteCategory(int catid) { qDebug() << "sql::deleteCategory(int catid)"; QSqlQuery q; //удаляем диски q.prepare("SELECT id from disc WHERE catid = ?"); q.addBindValue(catid); q.exec(); while(q.next()) { deleteDisc(q.value(0).toInt()); } // удаляем категорию q.prepare("DELETE FROM category WHERE id=?"); q.addBindValue(catid); q.exec(); return true; } bool sql::addDisc(QString name, QString descr, int year, int catid) { return true; } bool sql::isOpen() { return db.isOpen(); }
Название: Re: Приложение падает при emit в пользовательском классе.
Отправлено: Alex03 от Июнь 03, 2008, 06:28
Rebuild All (make clean ; make) не помогает?
Название: Re: Приложение падает при emit в пользовательском классе.
Отправлено: Arceny от Июнь 03, 2008, 08:22
Нет Кстати что любопытно. Генерация сигнала в другом методе не приводит к падению (сделал mysignal(int) некий). Что-бы это могло быть?
Название: Re: Приложение падает при emit в пользовательском классе.
Отправлено: Sergeich от Июнь 03, 2008, 10:14
Приаттач код
Название: Re: Приложение падает при emit в пользовательском классе.
Отправлено: Arceny от Июнь 03, 2008, 12:53
Приаттач код
Всего проекта? Прикладываю весь проект, это программа для каталогизации дисков. СУБД пока только sqlite тестировалась, соответственно при инициализации БД выбирать её. Сигнал генерируется в методе класса sql , вызываемого при удалении диска из какой-либо категории. З.Ы. писалось на Qt4.4 , под винду собирать не пробовал. http://slil.ru/25858903
Название: Re: Приложение падает при emit в пользовательском классе.
Отправлено: Sergeich от Июнь 03, 2008, 16:32
Собрал VS2005 на XP SP2. Собираться не хотел, писал что не может найти метода QSqlDatabase::connectionName :o Глянул в qsqldatabase.h - действительно нету, похоже какой-то косяк у Троллей. Заменил на QSqlDatabase::databaseName - все скомпилялось. Далее, при запуске выходил на Q_ASSERT в header()->setResizeMode(0, QHeaderView::Stretch) в myTree::myTree и filesTree::filesTree, добавил setColumnCount. Если не выбрать текущий элемент падало myTree::deleteDisc(), на строках QTreeWidgetItem *item = currentItem(); if(item->parent() == NULL)
где проверка item на 0! //NULL в С++ писать не принято. И наконец источник проблемы с сигналами - конструкция myTree::myTree(QWidget *parent) : QTreeWidget(parent) { //.... db = ((mainWindow*)parent)->db; //.... }
parent в данном случае - QSplitter, а не mainWindow, в итоге в db хранится хуй знает что. Если уж и писать такое то так: mainWindow* mw = qobject_cast<mainWindow> parent; if (mw) db = mw->db; else db = 0;
Нормальное решение - либо передавать db в параметрах конструктора, либо делать синглетон, где хранить db, cnf и все остальное что может существовать в единственном экземпляре. З.Ы. Я бы больше 3 за это поставил :)
Название: Re: Приложение падает при emit в пользовательском классе.
Отправлено: Sergeich от Июнь 03, 2008, 16:45
Какая-то херь получилась с QSqlDatabase::connectionName() :o При повторном открытии проекта он нашелся в qsqldatabase.h (открывал через VS), хотя при первом запуске он его в упор не хотел видеть, и глазами искал, и поиском - нету и все :o Счас с ним скомпилялось без проблем.
Название: Re: Приложение падает при emit в пользовательском классе.
Отправлено: Arceny от Июнь 04, 2008, 01:58
Какая-то херь получилась с QSqlDatabase::connectionName() :o При повторном открытии проекта он нашелся в qsqldatabase.h (открывал через VS), хотя при первом запуске он его в упор не хотел видеть, и глазами искал, и поиском - нету и все :o Счас с ним скомпилялось без проблем.
А версия Qt не успела обновиться? Походу это в 4.4 ввели. И я там не совсем корректно с БД разрываю соединение. За комментарии по коду спасибо. Щас уже чото делать нет сил, завтра (то есть сегодня) посмотрю поподробнее. Offtop: А ещё: раз модераторы матерятся, значит и пользователям можно? :-)
Название: Re: Приложение падает при emit в пользовательском классе.
Отправлено: Sergeich от Июнь 04, 2008, 12:16
Offtop: А ещё: раз модераторы матерятся, значит и пользователям можно? :-)
Если по делу и к месту - можно :D
Название: Re: Приложение падает при emit в пользовательском классе.
Отправлено: Godfather от Июнь 04, 2008, 14:46
из личного опыта хочу заметить что лучше всего открывтаь БД через QSqlDatabase::addDatabase("DRIVER", QUuid::createUuid().toString()); т.е. каждому соединению присваивать уникальный идентификатор, иначе 2ой экземпляр того же класса (при аналогичном драйвере) будет работать с тем же соединением, а не со своим, и убдет коллизия. и если первй закроет его, 2ой упадет при запросе ну и в деструкторе я пишу if(dbCon.isOpen()) db.Con.close(); ииначе в Debug Output ругается что соединение осталось открытым что типа нехорошо
Название: Re: Приложение падает при emit в пользовательском классе.
Отправлено: vregess от Июнь 04, 2008, 20:34
Offtop: А ещё: раз модераторы матерятся, значит и пользователям можно? :-)
Если по делу и к месту - можно :D Я бы не советовал. Не педагогично.
Название: Re: Приложение падает при emit в пользовательском классе.
Отправлено: Steven_Orko от Июнь 05, 2008, 16:54
Offtop: А ещё: раз модераторы матерятся, значит и пользователям можно? :-)
Если по делу и к месту - можно :D OFF: Модераторы не БОГИ. И им подражать не обязательно!!! )))
Название: Re: Приложение падает при emit в пользовательском классе.
Отправлено: ритт от Июнь 12, 2008, 03:18
офф: действительно...подражайте администраторам :)
|