Ошибка сегментации клонирования Qt QString
Вопрос
Я создаю свое первое Qt-приложение с помощью Qt Creator, и все шло нормально, пока я не начал получать странный SIGSEGV из строки, по-видимому, безвредной.
Это и есть ошибка:
Программа получила сигнал SIGSEGV, ошибка сегментации.0x0804e2fe в QBasicAtomicInt::ref (this=0x0) в /usr/lib/qt/include/QtCore/qatomic_i386.h:120
Путем обратного отслеживания исключения на gdb, Я обнаружил, что простой получатель передает нулевой указатель конструктору clone, когда я возвращаю свой атрибут.
Вывод обратной трассировки:
(gdb) backtrace
#0 0x0804e2fe in QBasicAtomicInt::ref (this=0x0) at /usr/lib/qt/include/QtCore/qatomic_i386.h:120
#1 0x0804eb1b in QString (this=0xbfcc8e48, other=@0xbfcc8e80) at /usr/lib/qt/include/QtCore/qstring.h:712
#2 0x0805715e in Disciplina::getId (this=0xbfcc8e7c) at disciplina.cpp:13
[...]
Проверка указателя, переданного конструктору QString:
(gdb) x 0xbfcc8e80
0xbfcc8e80 0xbfcc8e80:0x00000000
А это дисциплина.cpp:13
QString Disciplina::getId()
{
return id;
}
Итак, все указывает на то, что конструктор копирования QString получает пустой указатель, что для меня не имеет смысла. ID был объявлен как частная QString.
private:
QString id;
Ну, я понятия не имею, что могло бы происходить, и мои навыки отладки простираются лишь настолько далеко, так что если бы кто-нибудь мог подкинуть идею, я был бы очень рад.
Спасибо.
Редактировать
Дополнительный код, как и было запрошено.
дисциплина.ч
#ifndef DISCIPLINA_H
#define DISCIPLINA_H
#include <QString>
#include <QMap>
#include "curso.h"
#include "turma.h"
class Curso;
class Turma;
class Disciplina
{
private:
unsigned short int serie;
QString id;
QString nome;
Curso* curso;
QMap<unsigned int, Turma*> turmas;
public:
Disciplina(QString id, Curso* curso, QString nome, unsigned short int serie);
QString getId();
const Curso getCurso();
QString getNome();
void setNome(QString nome);
void addTurma(Turma* t, unsigned int id);
QMap<unsigned int, Turma*> getTurmas();
};
#endif // DISCIPLINA_H
disciplina.cpp
#include "disciplina.h"
Disciplina::Disciplina(QString id, Curso* curso, QString nome, unsigned short int serie)
{
this->id = id;
this->curso = curso;
this->nome = nome;
this->serie = serie;
}
QString Disciplina::getId()
{
return id;
}
const Curso Disciplina::getCurso()
{
const Curso c(*this->curso);
return c;
}
QString Disciplina::getNome()
{
return this->nome;
}
void Disciplina::setNome(QString nome)
{
this->nome = nome;
}
void Disciplina::addTurma(Turma* t, unsigned int id)
{
this->turmas.insert(id, t);
}
QMap<unsigned int, Turma*> Disciplina::getTurmas()
{
return this->turmas;
}
Функция вызывающего абонента (я разбил ее для облегчения отладки)
Disciplina*
MainWindow::getSelectedDisciplina()
{
if(ui->disciplinaTurma->count() > 0 && currentCurso)
{
QMap<QString, Disciplina*> qm(currentCurso->getDisciplinas());
QString key = ui->disciplinaTurma->itemText(ui->disciplinaTurma->currentIndex());
Disciplina* d = qm[key];
QMessageBox::information(this, d->getId(), d->getNome());
return d;
}
else
return NULL;
}
Решаемая
В Disciplina
объект, вставленный в карту, выходил из области видимости и поэтому удалялся.Поскольку, как указал Хасинто, Map создавала ванильное значение при попытке доступа к несуществующему ключу, это выглядело так, как будто объект был там.
Спасибо вам обоим Хасинто и что-то за твою помощь.
Решение
В map c ++, если элемент не существует, когда вы пытаетесь получить к нему доступ по его ключу, он просто создает его для вас.Вы пытаетесь сделать то же самое здесь, и если QMap работает таким же образом, это то, что вызывает ваш segfault.
Что вам следует сделать, так это проверить наличие ключа на карте, прежде чем обращаться к нему.
Редактировать:для пуристов C ++, пожалуйста, дайте мне знать, если у меня есть на это право.Я знаю, что на практике безопаснее протестировать, прежде чем обращаться к нему, но я не уверен, что фразеология "это создает его для вас" - очень хороший способ выразить это.Это может просто вернуть вам пространство в памяти, где было бы такое значение;Я не знаю, действительно ли это вызовет конструктор по умолчанию.
Другие советы
Может быть, тот Disciplina
объект, который вы вызываете getId()
вкл. был ранее удален, так что он больше не действителен.