【问题标题】:Qt QString cloning Segmentation FaultQt QString 克隆分段错误
【发布时间】:2009-12-07 18:30:18
【问题描述】:

我正在使用 Qt Creator 构建我的第一个 Qt 应用程序,一切都很顺利,直到我开始从一条看似无害的线路中得到一个奇怪的 SIGSEGV。

这是错误:

程序收到信号SIGSEGV,分段错误。 /usr/lib/qt/include/QtCore/qatomic_i386.h:120 处的 QBasicAtomicInt::ref (this=0x0) 中的 0x0804e2fe

通过回溯 gdb 上的异常,我发现当我返回属性时,一个简单的 getter 将 NULL 指针传递给克隆构造函数。

回溯输出:

(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: 0x00000000

这是 disciplina.cpp:13

QString Disciplina::getId()
{
    return id;
}

所以,所有指向 QString 的复制构造函数接收一个空指针,这对我来说毫无意义。 id 被声明为私有 QString。

private:
    QString id;

好吧,我不知道会发生什么,而且我的调试技能也只能到此为止,所以如果有人能提出一个想法,我会非常高兴。

谢谢。

编辑

根据要求提供更多代码。

disciplina.h

#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 对象超出范围,因此被删除。正如 Jacinto 指出的那样,由于 Map 在您尝试访问不存在的键时创建了一个普通值,所以看起来对象就在那里。

感谢 Jacintosth 的帮助。

【问题讨论】:

  • 与我的回答相吻合, currentCurso->getDisciplinas()) 是什么类型?如果它不是相同类型的键/值的 QMap,那么这不起作用。此外,当您可以访问原始地图时,为什么要创建地图的值类型副本?你在做什么对我来说没有多大意义。
  • 仅出于调试原因。我用一些冗余的方式分解了那里发生的所有事情,一次只踩一行。

标签: c++ qt pointers qstring


【解决方案1】:

在 c++ 的映射中,如果当您尝试通过其键访问该元素时该元素不存在,它只会为您创建一个。您在这里尝试做同样的事情,如果 QMap 的工作方式相同,这就是导致您的段错误的原因。

您应该做的是在访问之前测试密钥在地图中的存在。

编辑:对于 C++ 纯粹主义者,如果我有这个权利,请告诉我。我知道在实践中在访问它之前进行测试更安全,但我不知道“它为你创造一个”的措辞是否是一个很好的表达方式。它可能只是返回给你这样一个值所在的内存空间;我不知道它是否真的会调用默认构造函数。

【讨论】:

  • 这就是为什么我为了自己的理智而避免使用 [] 运算符。是的,它们更接近于地图是关联数组的概念,但实际上是一个根据上下文具有多种行为的运算符,而不是我的口味。
【解决方案2】:

也许您调用 getId()Disciplina 对象之前已被删除,因此它不再有效。

【讨论】:

  • 我认为这是不可能的,但在阅读了 Jacinto 关于地图的回答并查看了 QMap API 之后,我认为这正是问题所在。由于 StackOverflow 只接受一个要选择的答案,所以我选择了他的,但如果没有这两个答案,我就不会想到这一点。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多