views:

78

answers:

3

I'm a little new to object oriented programming, and very new to Qt and GUIs in general. I am now playing with this example in Nokia's Qt tutorial: http://doc.qt.nokia.com/4.1/tutorial-t5.html

I tried to extend the code; this is what I have now:

#include <QApplication>
#include <QFont>
#include <QLCDNumber>
#include <QPushButton>
#include <QSlider>
#include <QVBoxLayout>
#include <QWidget>

class MyWidget : public QWidget
{
public:
    MyWidget(QWidget *parent = 0);
};

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
{
    QPushButton *quit = new QPushButton(tr("Quit"));
    move(1600,0);
    quit->setFont(QFont("Times", 18, QFont::Bold));

    QPushButton* numbase;
    numbase = new QPushButton[4];
    numbase[0].setText("Dec");
    (numbase+1)->setText("Bin"); // Hihihi
    numbase[2].setText("Hex");
    numbase[3].setText("Oct");

    // a[i] == *(a+i)

    QLCDNumber *lcd = new QLCDNumber(8);
    lcd->setSegmentStyle(QLCDNumber::Filled);
    lcd->setMode(QLCDNumber::Hex);

    QSlider *slider = new QSlider(Qt::Horizontal);
    slider->setRange(0, 99);
    slider->setValue(0);

    connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
    connect(slider, SIGNAL(valueChanged(int)),
            lcd, SLOT(display(int)));

    connect(numbase+0, SIGNAL(clicked()), lcd, SLOT(setDecMode()));
    connect(numbase+1, SIGNAL(clicked()), lcd, SLOT(setBinMode()));
    connect(numbase+2, SIGNAL(clicked()), lcd, SLOT(setHexMode()));
    connect(numbase+3, SIGNAL(clicked()), lcd, SLOT(setOctMode()));

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(quit);
    layout->addWidget(lcd);
    layout->addWidget(slider);

    // Segmentation fault if I include those two lines:
    for(int i=0;i<4;i++)
        layout->addWidget(numbase+i);
    // -------------

    setLayout(layout);
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MyWidget widget;
    widget.show();
    return app.exec();
}

When I include the marked two lines, the program does its job correctly, but if I quit it (and only then) the console shows a "Segmentation fault". I'd like to know why that happens.

And also, is there a better way to reference the 4 widgets? (numbase+2) looks weird, is this really how I am supposed to do this?

A: 

A better way is to use a array of pointers, you should try it:

QPushButton *buttons[4];

buttons[0] = new QPushButton(this);
buttons[1] = new QPushButton(this);
buttons[2] = new QPushButton(this);
buttons[3] = new QPushButton(this);

buttons[0]->setText("foo")

connect(buttons[0], SIGNAL(clicked()), this, SLOT(bar()));
Matias Valdenegro
When will I finally grasp the pointers? :) Thanks. Array of pointers != pointer to array. I'll note that.
Alexx Hardt
@downvoter: Can i know why did you downvote?
Matias Valdenegro
does the crash disappear if you replace your code with one given by Matias ? ...
Ankur Gupta
Why is this -1? This is actually correct I was about to say the same. You need pointers in the array to use QPushButton as QWidget.
stribika
@Ankur: Yes. I'd like to know why exactly the segfault appears, though.
Alexx Hardt
I added the -1. Because OP asked why his code doesn't work, and this answer says nothing about this. Moreover, it forced Alexx into an accepting an incorrect conclusion that "Array of pointers != pointer to array" has *anything* to do with it.
Pavel Shved
A: 
  1. Try replacing 4 by 3 in the loop.

  2. If you want Qt to do garbage collection make sure you set the parent child relationship of widget correctly i.e. QPushButton resides in QWidget so set it in constructor.

  3. For simple UI like these try creating it using Qt Designer and see the generated code.

Ankur Gupta
I thought addWidget() takes care of the parent/child thing automatically. The other part of the code is from the Qt website, they didn't use it either.
Alexx Hardt
I am just letting you know about the best practices. Explicit is better than implicit. It's easy to read the code and see who is the parent of whom.
Ankur Gupta
+3  A: 

The possible reason of crash is that Qt, at deletion of the form, calls delete function for each widget on the form. So, at program exit, when destroying your form, Qt internals would execute the following sequence:

delete numbase[0];
delete numbase[1];
delete numbase[2];
delete numbase[3];

However, the correct way to free the memory would be

delete [] numbase;

because you allocated numbase with a special array allocation new[] operator, which is different from the usual new. And it's "undefined behavior" if you use delete instead of delete[] in C++. So, segmentation fault could happen if it's the case.

You can check if it's the reason, by allocating each emenent in your array separately, with new QPushButton;, as specified in the other answer.

Pavel Shved
Thanks! Where would I enter the delete[] line?
Alexx Hardt
@Alexx, it's not you who enters the `delete[]` line. It's internal Qt procedures which actually call `delete` operators (see my other answer http://stackoverflow.com/questions/3646300/why-cant-we-create-object-in-qt-without-the-new-keyword-i-e-on-stack/3646420#3646420 on this topic), and you can't change them. The best you could do is to allocate your objects in such a way that matches Qt's way of deallocating them. That means, not on stack, and not with `new[]` you used, but with causal `new` operator instead.
Pavel Shved
I didn't know I walked on forbidden land :) I'll use pointer arrays from now on, thanks!
Alexx Hardt