为啥这个代码在 w.show() 调用中会出现段错误?

Posted

技术标签:

【中文标题】为啥这个代码在 w.show() 调用中会出现段错误?【英文标题】:Why does this code segfault on the w.show() call?为什么这个代码在 w.show() 调用中会出现段错误? 【发布时间】:2014-08-11 10:10:25 【问题描述】:

主题说明了一切,代码如下:

我正在使用带有 qt-opensource-windows-x86-mingw482_opengl-5.3.1 的 windows 7 64 位

我在下面发布了受影响的代码。在调试崩溃时,我在 main.cpp 文件中的 w.show() 行上得到一个段错误

编辑: 抱歉忘记补充,如果我注释掉该行,它不会崩溃:

//mainLayout->addLayout(oldLayout,0,0,1,1,Qt::AlignLeft);

然后它会正确显示带有小部件的主窗口,但是当我尝试向布局添加布局时,它崩溃了...

main.cpp:

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();

主窗口.cpp

#include <QLabel>
#include <QString>

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)

    setupWidgets();    



void MainWindow::setupWidgets() 

    mainWidget = new QWidget;
    mainLayout = new QGridLayout;

    setupOld();    

    setCentralWidget(mainWidget);
    mainWidget->setLayout(mainLayout);
    mainLayout->addLayout(oldLayout,0,0,1,1,Qt::AlignLeft);


void MainWindow::setupOld() 
    oldLayout = new QGridLayout;

    oldX = new QDoubleSpinBox;
    oldX->setRange(minNum,maxNum);
    oldX->setDecimals(precision);
    oldX->setSuffix(suffix);

    oldY = new QDoubleSpinBox;
    oldY->setRange(minNum,maxNum);
    oldY->setDecimals(precision);
    oldY->setSuffix(suffix);

    oldZ = new QDoubleSpinBox;
    oldZ->setRange(minNum,maxNum);
    oldZ->setDecimals(precision);
    oldZ->setSuffix(suffix);

    QLabel lblX, lblY, lblZ;
    lblX.setText("Old X Coord: ");
    lblY.setText("Old Y Coord: ");
    lblZ.setText("Old Z Coord: ");

    oldLayout->addWidget(&lblX,0,0,1,1,Qt::AlignLeft);
    oldLayout->addWidget(oldX,0,1,1,1,Qt::AlignLeft);
    oldLayout->addWidget(&lblY,1,0,1,1,Qt::AlignLeft);
    oldLayout->addWidget(oldY,1,1,1,1,Qt::AlignLeft);
    oldLayout->addWidget(&lblZ,2,0,1,1,Qt::AlignLeft);
    oldLayout->addWidget(oldZ,2,1,1,1,Qt::AlignLeft);

【问题讨论】:

这通常是由空指针引起的,检查你的对象的属性 默认构造函数在哪里? @quantdev 通常是MainWindow(QWidget* parent=0)(也就是使用默认参数) 【参考方案1】:

我认为原因在于以下代码:

QLabel lblX, lblY, lblZ;
[..]
oldLayout->addWidget(&lblX,0,0,1,1,Qt::AlignLeft);

您在堆栈中创建标签对象并在布局中使用它们。执行存在MainWindow::setupOld() 函数后,标签正在删除,因此您的布局包含对已删除对象的引用。

要解决这个问题,您需要像为QDoubleSpinBoxes 那样创建从堆分配内存的标签:

QLabel *lblX = new QLabel("Old X Coord: ");
[..]
oldLayout->addWidget(lblX,0,0,1,1,Qt::AlignLeft);

【讨论】:

@vahancho 谢谢,是的,创建了指针标签,现在它可以工作了:)【参考方案2】:

下面的作品。请注意我是如何剔除重复代码,将所有对象作为MainWindow 的直接成员,并在构造函数中利用初始化列表的。

如果您不想使用它的其他功能(停靠区、状态栏等),您不必使用QMainWindow。在下面的代码中,您可以轻松地将QMainWindow 替换为QWidget,并进行以下其他更改:

    this而不是m_central上设置布局,

    删除setCentralWidget 调用。

#include <QApplication>
#include <QMainWindow>
#include <QLabel>
#include <QGridLayout>
#include <QDoubleSpinBox>

class MainWindow : public QMainWindow 
   QWidget m_central;
   QGridLayout m_centralLayout;
   QDoubleSpinBox m_oldX, m_oldY, m_oldZ;
   QLabel m_lblX, m_lblY, m_lblZ;
public:
   MainWindow(QWidget * parent = 0, Qt::WindowFlags flags = 0);
;

MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) :
   QMainWindow(parent, flags),
   m_centralLayout(&m_central),
   m_lblX("Old X Coord: "),
   m_lblY("Old Y Coord: "),
   m_lblZ("Old Z Coord: ")

   QList<QDoubleSpinBox*> spins;
   spins << &m_oldX << &m_oldY << &m_oldZ;
   int i = 0;
   foreach (QDoubleSpinBox * spin, spins) 
      spin->setRange(0.0, 1.0);
      spin->setDecimals(3);
      spin->setSuffix(" km");
      m_centralLayout.addWidget(spin, i++, 1);
   

   m_centralLayout.addWidget(&m_lblX, 0, 0);
   m_centralLayout.addWidget(&m_lblY, 1, 0);
   m_centralLayout.addWidget(&m_lblZ, 2, 0);

   setCentralWidget(&m_central);


int main(int argc, char *argv[])

   QApplication a(argc, argv);
   MainWindow w;
   w.show();
   return a.exec();

【讨论】:

以上是关于为啥这个代码在 w.show() 调用中会出现段错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Stackdriver 日志中会间歇性出现空行?

为啥python中会出现这个AttributeError?

为啥这样的 penAL 代码在 Visual Studio 2008 中会出现这样的错误?

为啥 Corona sdk 中会出现此错误?

为啥 Eclipse 中会出现重复的方法建议?

为啥在 PageViewController 中会出现这种类型的滚动?