0

I have a class with a lot of member functions. Here are the ones giving me trouble (Segmentation Fault):

#include "mainwindow.h"
#include <QTimer>
#include <QDebug>
#include <QMessageBox>
#include "ui_mainwindow.h"
#include "LabJackUD.h"

MainWindow::MainWindow(QWidget *parent, LJ_HANDLE *lngHandle2) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    blah
}

MainWindow::~MainWindow(){delete ui;}

void MainWindow::resetHandle() {
    //Open the first found LabJack U3.
    lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, lngHandle);
    runningErrors(lngErrorcode, __LINE__, 0);

    lngErrorcode = GoOne(*lngHandle);
    runningErrors(lngErrorcode, __LINE__, 0);
}

void MainWindow::runningErrors(LJ_ERROR lngErrorcode, long lngLineNumber, long lngIteration) {
    char err[255];

    if((lngErrorcode == 1015) && (!isOpen))
    {
        isOpen = true;

        //STOP EVERYTHING
        MainWindow::on_pushButton_clicked(false);
        //Create an error message dialog only to prompt to connect labjack.
        QMessageBox *msg = new QMessageBox();
        msg->show();
        msg->setText("WARNING:\n\nLabjack is not connected. Please\nconnect Labjack.");

    }

    if(lngErrorcode == 1003)
    {
        //attempt to solve handle problem by resetting handle
        OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, lngHandle);
        GoOne(*lngHandle);
    }

    if(lngErrorcode != LJE_NOERROR)
    {
        ui->textBrowser->show();
        ui->exitTextBrowser->show();

        ErrorToString(lngErrorcode,err);
        ui->textBrowser->setText(err);
    }
}


void MainWindow::update_timer_complete()
{

    //Display new LCD values
    //qDebug()<<"updateLCDs timeout";
    QString minutesTop = QString::number((cycleComplete->remainingTime()/1000)/7);
    QString secondsTop = QString::number((cycleComplete->remainingTime()/1000)%7);
    QString minutesBot = QString::number((nextExperiment->remainingTime()/1000)/7);
    QString secondsBot = QString::number((nextExperiment->remainingTime()/1000)%7);

    ui->lcdNumber->display(minutesTop+":"+secondsTop);
    ui->lcdNumber_2->display(minutesBot+":"+secondsBot);

    minutesTop.~QString();
    minutesBot.~QString();
    secondsTop.~QString();
    secondsBot.~QString();

    //I really wanted to check if stuff is working during each update.
    resetHandle(); //Will call runningError() handler if problem
}

I can call my error handling function runningError() from any member function except void update_timer_complete(). When I do, I get a .exe crash.

There were a lot more member functions omitted.

If this helps, here is the class definition header file:

#include <QMainWindow>
#include "LabJackUD.h"
#include <QTimer>


namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0, LJ_HANDLE* lngHandle = 0);
    ~MainWindow();

private slots:
    void cycle_timer_complete();

    void next_timer_complete(bool update = false);

    void update_timer_complete();

    void on_radioButton_pressed();

    void on_radioButton_2_pressed();

    void on_radioButton_released();

    void on_radioButton_3_pressed();

    void on_radioButton_4_pressed();

    void on_pushButton_toggled(bool checked);

    void on_pushButton_clicked();

    void on_pushButton_4_clicked();

    void on_pushButton_clicked(bool checked);

    void on_exitTextBrowser_clicked();

private:
    Ui::MainWindow *ui;
    LJ_HANDLE *lngHandle;
    LJ_ERROR lngErrorcode;
    void clearAll();
    void runningErrors(LJ_ERROR lngErrorcode, long lngLineNumber, long lngIteration);
    QTimer *cycleComplete;
    QTimer *nextExperiment;
    QTimer *updateLCDs;
    int selectedPin;
    int timer1;
    int timer2;
    int timer3;
    int prevTime, prevSpin1, prevSpin2, prevSpin3, prevSpin4;
    void resetHandle();
    void updatePins();
};

What could allow two equivalent member functions of the form private void doStuff() to have unequal access to the same member function? One calls it fine, the other calls it and produces a segmentation fault!

If really required, here is the full code:

    #include "mainwindow.h"
#include <QTimer>
#include <QDebug>
#include <QMessageBox>
#include "ui_mainwindow.h"
#include "LabJackUD.h"

bool isOpen = false;

MainWindow::MainWindow(QWidget *parent, LJ_HANDLE *lngHandle2) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    lngHandle = lngHandle2;
    cycleComplete = new QTimer(this);
    nextExperiment = new QTimer(this);
    updateLCDs = new QTimer(this);
    selectedPin = 0;
    timer1 = 0;
    timer2 = 0;
    timer3 = 0;
    lngErrorcode = 0;

    connect(cycleComplete,SIGNAL(timeout()),this,SLOT(cycle_timer_complete()));
    connect(nextExperiment,SIGNAL(timeout()),this,SLOT(next_timer_complete()));
    connect(updateLCDs,SIGNAL(timeout()),this,SLOT(update_timer_complete()));

    ui->textBrowser->hide();
    ui->textBrowser->raise();
    ui->exitTextBrowser->hide();
    ui->exitTextBrowser->raise();

    clearAll();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::resetHandle() {
    //Open the first found LabJack U3.
    lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, lngHandle);
    runningErrors(lngErrorcode, __LINE__, 0);

    lngErrorcode = GoOne(*lngHandle);
    runningErrors(lngErrorcode, __LINE__, 0);
}

void MainWindow::runningErrors(LJ_ERROR lngErrorcode, long lngLineNumber, long lngIteration) {
    char err[255];

    if((lngErrorcode == 1015) && (!isOpen))
    {
        isOpen = true;

        //STOP EVERYTHING
        MainWindow::on_pushButton_clicked(false);
        //Create an error message dialog only to prompt to connect labjack.
        QMessageBox *msg = new QMessageBox();
        msg->show();
        msg->setText("WARNING:\n\nLabjack is not connected. Please\nconnect Labjack.");

    }

    if(lngErrorcode == 1003)
    {
        //attempt to solve handle problem by resetting handle
        OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, lngHandle);
        GoOne(*lngHandle);
    }

    if(lngErrorcode != LJE_NOERROR)
    {
        ui->textBrowser->show();
        ui->exitTextBrowser->show();

        ErrorToString(lngErrorcode,err);
        ui->textBrowser->setText(err);

        //Qdebugging purposes
        qDebug() << ("Error number = ") << lngErrorcode;
        qDebug() << ("Error string = ") << err;
        qDebug() << ("Source line number = ") << lngLineNumber;
        qDebug() << ("Iteration = ") << lngIteration;

    }
}

void MainWindow::clearAll() {
    lngErrorcode = eDO(*lngHandle, 4, 0);
    runningErrors(lngErrorcode, __LINE__, 0);
    lngErrorcode = eDO(*lngHandle, 5, 0);
    runningErrors(lngErrorcode, __LINE__, 0);
    lngErrorcode = eDO(*lngHandle, 6, 0);
    runningErrors(lngErrorcode, __LINE__, 0);
    lngErrorcode = eDO(*lngHandle, 7, 0);
    runningErrors(lngErrorcode, __LINE__, 0);
    ui->radioButton->setChecked(false);
    ui->radioButton_2->setChecked(false);
    ui->radioButton_3->setChecked(false);
    ui->radioButton_4->setChecked(false);
}

void MainWindow::on_radioButton_pressed()
{
    clearAll();
    lngErrorcode = eDO(*lngHandle, 4, 1);
    runningErrors(lngErrorcode, __LINE__, 0);
    qDebug() << "radio button 1 pressed";
    ui->radioButton->setChecked(true);
}

void MainWindow::on_radioButton_2_pressed()
{
    clearAll();
    lngErrorcode = eDO(*lngHandle, 5, 1);
    runningErrors(lngErrorcode, __LINE__, 0);
    qDebug() << "radio button 2 pressed";
    ui->radioButton_2->setChecked(true);
}


void MainWindow::on_radioButton_3_pressed()
{
    clearAll();
    lngErrorcode = eDO(*lngHandle, 6, 1);
    runningErrors(lngErrorcode, __LINE__, 0);
    qDebug() << "radio button 3 pressed";
    ui->radioButton_3->setChecked(true);
}


void MainWindow::on_radioButton_4_pressed()
{
    clearAll();
    lngErrorcode = eDO(*lngHandle, 7, 1);
    runningErrors(lngErrorcode, __LINE__, 0);
    qDebug() << "radio button 4 pressed";
    ui->radioButton_4->setChecked(true);
}

void MainWindow::on_pushButton_toggled(bool checked)
{
}

void MainWindow::on_pushButton_clicked()
{

}

void MainWindow::cycle_timer_complete()
{
    qDebug()<<"cycleComplete timeout";
}

void MainWindow::next_timer_complete(bool update)
{
    qDebug()<<"nextExperiment timeout";
    if (!update) {
    selectedPin++;
    }

    qDebug()<<"selectedPin is " << selectedPin;

    switch ( selectedPin ) {
    case 4:
        qDebug() << "case 4";
        if (!update) {
        nextExperiment->start((ui->spinBox->value())*1000*7);
        }
        MainWindow::on_radioButton_pressed();
        break;
    case 5:
        qDebug() << "case 5";
        nextExperiment->start((ui->spinBox_2->value())*1000*7);
        MainWindow::on_radioButton_2_pressed();
        break;
    case 6:
        qDebug() << "case 6";
        nextExperiment->start((ui->spinBox_3->value())*1000*7);
        MainWindow::on_radioButton_3_pressed();
        break;
    case 7:
        qDebug() << "case 7";
        nextExperiment->start((ui->spinBox_4->value())*1000*7);
        MainWindow::on_radioButton_4_pressed();
        break;
    case 8:
        qDebug() << "case 8";
        MainWindow::on_pushButton_clicked(true);
        break;
    }


    //ui->pushButton->setText("Timer Complete");
}

void MainWindow::update_timer_complete()
{

    //Display new LCD values
    //qDebug()<<"updateLCDs timeout";
    QString minutesTop = QString::number((cycleComplete->remainingTime()/1000)/7);
    QString secondsTop = QString::number((cycleComplete->remainingTime()/1000)%7);
    QString minutesBot = QString::number((nextExperiment->remainingTime()/1000)/7);
    QString secondsBot = QString::number((nextExperiment->remainingTime()/1000)%7);

    ui->lcdNumber->display(minutesTop+":"+secondsTop);
    ui->lcdNumber_2->display(minutesBot+":"+secondsBot);

    minutesTop.~QString();
    minutesBot.~QString();
    secondsTop.~QString();
    secondsBot.~QString();

    //I really wanted to check if stuff is working during each update.
    resetHandle();
}

void MainWindow::on_pushButton_4_clicked()
{
    //figure out the total cycle time
    int t_total = ui->spinBox->value();
    t_total += ui->spinBox_2->value();
    t_total += ui->spinBox_3->value();
    t_total += ui->spinBox_4->value();

    //continue counting from previous state, correct for new values
    int newCycleTime = timer1;
    int newExpTime = timer2;
    int c1 = ui->spinBox->value();
    int c2 = ui->spinBox_2->value();
    int c3 = ui->spinBox_3->value();
    int c4 = ui->spinBox_4->value();
    switch(selectedPin) {
    case 4:
        newExpTime += (c1 - prevSpin1)*1000*7;
        newCycleTime += (c1+c2+c3+c4-prevSpin1-prevSpin2-prevSpin3-prevSpin4)*1000*7;
    case 5:
        newExpTime += (c2 - prevSpin2)*1000*7;
        newCycleTime += (c2+c3+c4-prevSpin2-prevSpin3-prevSpin4)*1000*7;
    case 6:
        newExpTime += (c3 - prevSpin3)*1000*7;
        newCycleTime += (c3+c4-prevSpin3-prevSpin4)*1000*7;
    case 7:
        newExpTime += (c4 - prevSpin4)*1000*7;
        newCycleTime += (c4-prevSpin4)*1000*7;
    }
    cycleComplete->start(newCycleTime);
    nextExperiment->start(newExpTime);
    updateLCDs->start(timer3);

    //change back appearance
    ui->pushButton_4->setEnabled(false);
    ui->pushButton->setText("STOP");
    ui->radioButton->setEnabled(false);
    ui->radioButton_2->setEnabled(false);
    ui->radioButton_3->setEnabled(false);
    ui->radioButton_4->setEnabled(false);
    ui->pushButton->setChecked(true);

    prevSpin1 = c1;
    prevSpin2 = c2;
    prevSpin3 = c3;
    prevSpin4 = c4;

    //no dialog open so reset
    isOpen=false;
}

void MainWindow::on_radioButton_released()
{
}

void MainWindow::on_pushButton_clicked(bool checked)
{
    if(checked) {
        //START NRML OPERATION
        //selectedPin will become 4 very shortly.
        selectedPin = 3;
        //figure out the total cycle time
        int t_total = ui->spinBox->value();
        t_total += ui->spinBox_2->value();
        t_total += ui->spinBox_3->value();
        t_total += ui->spinBox_4->value();
        t_total *= 1000*7;
        //keep track for continue option.
        prevTime = t_total;
        //configure timers
        cycleComplete->setInterval(t_total);
        nextExperiment->setInterval(0);
        updateLCDs->setInterval(100);

        ui->pushButton->setText("STOP");
        ui->radioButton->setEnabled(false);
        ui->radioButton_2->setEnabled(false);
        ui->radioButton_3->setEnabled(false);
        ui->radioButton_4->setEnabled(false);
        ui->pushButton_4->setEnabled(false);
        ui->spinBox->setEnabled(false);
        ui->spinBox_2->setEnabled(false);
        ui->spinBox_3->setEnabled(false);
        ui->spinBox_4->setEnabled(false);

        //start timers
        cycleComplete->start();
        nextExperiment->start();
        updateLCDs->start();

        //no dialog open so reset
        isOpen=false;
    } else {
        //STOP EVERYTHING REVERT EVERYTHING
        //enable continue button
        ui->pushButton_4->setEnabled(true);

        //revert appearance
        ui->pushButton->setText("START");
        ui->radioButton->setEnabled(true);
        ui->radioButton_2->setEnabled(true);
        ui->radioButton_3->setEnabled(true);
        ui->radioButton_4->setEnabled(true);
        ui->spinBox->setEnabled(true);
        ui->spinBox_2->setEnabled(true);
        ui->spinBox_3->setEnabled(true);
        ui->spinBox_4->setEnabled(true);

        //copy the current state for continuing
        //+1 because finished timer is -1
        timer1 = (cycleComplete->remainingTime()+1);
        timer2 = (nextExperiment->remainingTime()+1);
        timer3 = (updateLCDs->remainingTime()+1);
        prevSpin1 = ui->spinBox->value();
        prevSpin2 = ui->spinBox_2->value();
        prevSpin3 = ui->spinBox_3->value();
        prevSpin4 = ui->spinBox_4->value();

        //stop the timers
        cycleComplete->stop();
        nextExperiment->stop();
        updateLCDs->stop();
    }
}

void MainWindow::on_exitTextBrowser_clicked()
{
    ui->textBrowser->hide();
    ui->exitTextBrowser->hide();
}
JoseOrtiz3
  • 1,785
  • 17
  • 28

1 Answers1

0

Strangely, the solution was rearange the body of the definition of the member function void update_timer_complete() {body}. I had to put

    //I really wanted to check if stuff is working during each update.
resetHandle(); //Will call runningError() handler if problem

above

    //Display new LCD values
//qDebug()<<"updateLCDs timeout";
QString minutesTop = QString::number((cycleComplete->remainingTime()/1000)/7);
QString secondsTop = QString::number((cycleComplete->remainingTime()/1000)%7);
QString minutesBot = QString::number((nextExperiment->remainingTime()/1000)/7);
QString secondsBot = QString::number((nextExperiment->remainingTime()/1000)%7);

ui->lcdNumber->display(minutesTop+":"+secondsTop);
ui->lcdNumber_2->display(minutesBot+":"+secondsBot);

minutesTop.~QString();
minutesBot.~QString();
secondsTop.~QString();
secondsBot.~QString();

For some reason, the other way around produces a crash. I would love to hear an explanation, and if one is given, I will select it as the answer.

JoseOrtiz3
  • 1,785
  • 17
  • 28
  • Why are you calling the QString destructors?! That doesn't delete them, but they'll be destroyed automatically (and the destructors called) when they go out of scope, ie at the end of the update_timer_complete() method. – Hamish Moffatt Apr 15 '15 at 01:14
  • Calling the destructor of your `QString` objects will cause them to be destroyed twice. This is undefined behavior. You shouldn't do that. Remove those calls to the destructors. – thuga Apr 15 '15 at 07:57
  • Thanks guys. The object is destroyed when it goes out of scope, makes sense! Its only if you declare a pointer to a new object that the pointer will be destroyed leaving the object dangling. http://stackoverflow.com/questions/10081429/when-is-a-c-destructor-called – JoseOrtiz3 Apr 17 '15 at 18:57