Search code examples
c++qtsegmentation-faultpass-by-reference

Segmentation Fault happening when trying to pass objects by reference in qt program


I am using Qt and have made it so that two dialogs appear before my centralwidget. Inside my second dialog (playerInfo) I created a QcomboBox and a QlineEdit that takes in an int and a QString. I then store those values into my player class. However when I create my centralwidget and try to pass the player objects into it, it segfaults.

my main.cpp

int main( int argv, char* argc[] ) {
    int numberPlayers = 0;
  QApplication app( argv, argc );
  MainWindow mw;
  numPlayers pPlayers; //first dialog that prompts the user to enter in how many players
   numberPlayers = pPlayers.returnInput();
 playerInfo *pInfo = new playerInfo(numberPlayers, &mw); //user enters in each players info based off number of players
  pInfo->show();
  return app.exec();
}

playerInfo Dialog:

#include "playerinfo.h"
using namespace std;

playerInfo::playerInfo( int players, MainWindow *mw, QWidget *parent) :
    QWidget(parent)
{
    max_players = players;
    wm = mw; //set wm to point to the address of the mainwindow object

    setFixedSize(400, 400);
    layout= new QVBoxLayout;
    this->setLayout(layout);

    title = new QLabel(tr("Please enter the following information:"));
    layout->addWidget(title);

    lineEdit = new QLineEdit; // create line edit
    layout->addWidget(lineEdit);

    comboBox = new QComboBox; // create combo box and add items to it
    QStringList items = QStringList() << "Hat" << "Car" << "Shoe" << "SpaceShip" << "Basketball" << "Ring";
    comboBox->addItems(items);
    layout->addWidget(comboBox);

    okay = new QPushButton(tr("Accept"));
    layout -> addWidget(okay);
    connect(okay, SIGNAL(clicked()), this, SLOT(storeInfo()));
}

QString playerInfo::getName() const
{
    return lineEdit->text();
}

int playerInfo::getIndex() const
{
    return comboBox->currentIndex();
}

void playerInfo::storeInfo()
{
    hide();
     index = getIndex();
    name = getName();
    wm->setPlayerData(index, name, pCounter);
    pCounter++;
    if (pCounter != max_players)
    {
         show();
    }
    else if (pCounter == max_players)
    {

        wm->setGUIWidgets(max_players);
        wm->createCentralWidget();
        wm->show();
    }

}

My centralwidget.cpp:

#include "centralwidget.h"
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;

CentralWidget::CentralWidget(Player *players[0], int input): QWidget() {

   for (int i = 0; i < input; i ++) 
   {
      p.append(players[i]); << still segfaulting
    // p[i] = players[i]; // segfaulting here <<<
   }
}

I figured out the area that is causing my program to segfault is when i try and pass the addresses of the players I passed in from playerInfo Dialog into private variables of the CentralWidget class. (p[i] = players[i];). Am I passing by reference incorrectly?

If there is anymore information you need (like the header files) please let me know. Thanks for any help.

Edit ::

#ifndef CENTRALWIDGET_H
#define CENTRALWIDGET_H
#include <QWidget>
#include <QtGui>
#include "player.h"

class CentralWidget: public QWidget {
  Q_OBJECT

  private:
   QVector<Player> *p;


  private slots:

 public:
    CentralWidget(Player *players[0], int input);

};

#endif

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtGui>
#include <iostream>
#include "guiplayervertical.h"
#include "centralwidget.h"

class MainWindow : public QMainWindow {
  Q_OBJECT

  private:
  Player *players[4];
  GUIPlayer* guiPlayers[4];
  QWidget *centralWidget;

  int input;
QList<int> index;
QList<QString> name;


  public:
    MainWindow();
    void setPlayerData(int _index, const QString &_name, int i);
    void setGUIWidgets(int input);
    void createCentralWidget();

};
#endif

mainwindow.cpp

#include "mainwindow.h"
using namespace std;
MainWindow::MainWindow() {
}


void MainWindow::setPlayerData(int _index, const QString &_name, int i)
{
    index.append(_index); // index is a member variable declared somewhere in your mainwindow.h
    name.append(_name); // name is a member variable declared somewhere in your mainwindow.h
    players[i] = new Player(name[i], index[i]);
    guiPlayers[i] = new GUIPlayerVertical( players[i]);
}


void MainWindow::setGUIWidgets(int input)
{
  if (input == 2)
  {
    addDockWidget( Qt::LeftDockWidgetArea, guiPlayers[0] );
    addDockWidget( Qt::RightDockWidgetArea, guiPlayers[1] );
  }
  else if (input == 3)
  {
    addDockWidget( Qt::LeftDockWidgetArea, guiPlayers[0] );
    addDockWidget( Qt::LeftDockWidgetArea, guiPlayers[1] );
    addDockWidget( Qt::RightDockWidgetArea, guiPlayers[2] );
  }
  else
  {
    addDockWidget( Qt::LeftDockWidgetArea, guiPlayers[0] );
    addDockWidget( Qt::LeftDockWidgetArea, guiPlayers[1] );
    addDockWidget( Qt::RightDockWidgetArea, guiPlayers[2] );
    addDockWidget( Qt::RightDockWidgetArea, guiPlayers[3] );
  }
}

void MainWindow::createCentralWidget()
{
    centralWidget = new CentralWidget(&players[0], input);

    setCentralWidget( centralWidget );
}

Solution

  • I have not really dug up the issue you encountered, because your code is too connected, and still misses some information. For example, the user's input is not defined, so if the number of players exceeded 4, it would have segfaulted.

    However, some of the coding practices in place are worth some refactoring. Since you are having issues with the assignment of p, which is copied from a pointer to an array passed as parameter, I suggested you switch to a more flexible and less error-prone method. Using std::vector or, in this case, QVector, you benefit from a variable-size array, with better memory management, instead of recreating yourself another container, or relying on a fixed-size array.

    Start at the member of your class, and declare

    private:
        QVector<Player*> players;
    

    Then, fill your container using

    players.append( new Player(name[i], index[i]) );
    

    When passing the vector as parameter to the constructor of your other class, use a const reference of the same type, this is the equivalent of passing a single pointer, not the whole object

    CentralWidget(const QVector<Player*>& players);
    

    Note that using the container, you do not need to also give the array size separately. Finally, this simplifies a lot of the remaining changes. You can now pass the whole member as parameter

    centralWidget = new CentralWidget(players);
    

    And simply copy it using

    p = players;
    

    No need for the for loop anymore.