QT: Memory Issue. Can't access a Class "[SOLVED]"



  • If Qt Works like regular C++, how come i can't access my class object using methods? For example, I declared a pointer to a foo object in the private field of the class MainWindow.h
    I have a method called setFoo() as a function for class MainWindow that instantiate the foo object. The setFoo() function is called from an event when a button is pressed, which I called on_button_1_clicked. I can access my foo class within this function. However when I call on_button_2_clicked, the foo class is inaccessible.

    @void MainWindow::on_pushButton_1_clicked() {
    this->setFoo();
    qDebug() << QString::fromStdString(this->confirmName());
    } @

    The code above will print out one of my class data elements.

    @void MainWindow::on_pushButton_2_click() {
    qDebug() << QString::fromStdString(this->confirmName());
    }@

    The code above will print out nothing.

    I'm new to QT5 and any help will be great since i've been banging my head over this for a while, and maybe its the wrong way to approach QT in general.


  • Moderators

    Why don't you use the MainWindow constructor to set your private member variable instead of an initializer function?

    Maybe it's better to provide us a minimal working example that illustrates your issues.



  • It is because I don't want to create an object immediately, but after someone presses button one, it'll feed in the numbers of players . setFoo() is actually setFoo(int).


  • Moderators

    So you are making a game and want to add users with your setFoo(int) function?

    Could it be that in situation 2 you don't have a user because you didn't call setFoo(int) and therefor there is no string to print?

    Again, we could help more if we get to see more of your code. A minimal program is enough.



  • The Complete Code:

    MainWindow.h

    @#ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #include "Board.h"
    #include <string>

    namespace Ui {
    class MainWindow;
    }

    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    explicit MainWindow(QWidget *parent = 0);
    void setPlayer(int);
    std::string getName();
    std::string confirmName();

    ~MainWindow();

    private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

    private:
    Ui::MainWindow *ui;
    Board * board;
    };@

    MainWindow.cpp

    @#include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "Board.h"
    #include <string>
    #include <QDebug>

    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);
    }

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

    void MainWindow::on_pushButton_clicked()
    {
    this->setPlayer(2);
    qDebug() << QString::fromStdString(this->confirmName());
    }

    void MainWindow::on_pushButton_2_clicked()
    {
    qDebug() << QString::fromStdString(this->confirmName());
    }

    void MainWindow::setPlayer( int num ) {
    board= new Board( num );
    std::string name_string[2] = {"INPUT1","INPUT2"};
    board->addNames( name_string );
    qDebug() << QString::fromStdString( getName() ) << endl;
    }

    std::string MainWindow::confirmName() {
    qDebug() << "Confirming Name" << endl;
    this->board->test();
    Player ** tmp_player = this->board->getPlayer();
    std::string tmp_string = tmp_player[0]->getName();
    return tmp_string;
    }@

    The board object is quite extensive but it works for sure since it was once a console application, I've added as much of the code as i can without anything related to the board. I've also tested without Qt for my situation and it prints properly.

    I didn't call setFoo(int) because i didn't want to reinitialized the board and lose all the game logic thus far


  • Moderators

    When you say it is not accessible, how do you mean exactly? Is there an error? Is nothing being printed at all? Or is an empty/null string being printed?

    Have you double checked that your slots are being called correctly (no typos in the CONNECTs and/or your button item names are correct (if you're using autoconnect funcionality))



  • There is no error, a empty/null string is probably being printed. push button 1 cause my class to
    print its values. Here is what the output looks like:

    /clicked button1/
    "INPUT1"

    Confirming Name

    "INPUT1"
    /clicked button2/

    Confirming Name

    ""


  • Lifetime Qt Champion

    Hi,

    To add to my fellow programmers, each time you call setPlayer your are creating a new board, so you have a memory leak and are "losing" one player each time.

    Also, if you call on_pushButton_2_clicked first, your application will crash since you have no board yet



  • SGaist you are correct, but this is a test run, and that button would not be available till after button 1 i s clicked. My question is how i would fix this issue if a memory leak is indeed the problem. I'm trying to dynamically instantiate the class depending on user input. First the user sets the number through a combo box, then he presses button 1. However, in this example, i arbitrarily set the number of players to 2 to test.

    I don't think I'm losing any single players, i'm just losing the entire board, which includes all the players and other objects inside. Thats why button 1 will be delete once it has finished its goal of instantiating board.


  • Moderators

    Is line 31 above the only place where a new board is constructed? Or could there be another one being created someplace else within your code?

    Incidentally, with the code as written, each click of button 1 will create a new board object and leave the old one sitting out there orphaned.

    There's got to be a logic error somewhere. It's not a Qt issue, that I'm sure of.



  • Line 31 is indeed the only line that will be used, and only once. I will disabled it afterwards, but for the sake of clarity, and to make sure nothing gets orphaned, it is left enabled.


  • Moderators

    Hi,

    Try these tricks to help pinpoint the issue:

    • Add some debug output in your Board constructor and destructor. This will help double-check that only 1 board is ever created, and that it doesn't get destroyed,
    • In confirmName(), print the Board's address too, and check that it never changes:
      @qDebug() << this->board;@

    What outputs do you get?

    [quote]
    @
    Player ** tmp_player = this->board->getPlayer();
    std::string tmp_string = tmp_player[0]->getName();[
    @
    [/quote]I presume getPlayer() returns an array of Players? I recommend:

    • Renaming the function to getPlayers() (plural) for clarity
    • Returning std::vector<Player*> for safety

    Then, print tmp_player.size()



  • Unfortunately, I started this project completely fresh to C++ and went the array route. I would need to go back and change everything to vector, i recon that might be the problem, but it worked fine without QT and gui, so it might not be either. I'll be trying to modify it to vector in the meantime.

    Also, yes, constructor for board is called once and never deconstructed.


  • Moderators

    [quote author="ath001" date="1395440315"]Unfortunately, I started this project completely fresh to C++ and went the array route. I would need to go back and change everything to vector, i recon that might be the problem, but it worked fine without QT and gui, so it might not be either. I’ll be trying to modify it to vector in the meantime.[/quote]That's OK. It's probably better to investigate further before rewriting large chunks of your code (which might introduce other bugs).

    Memory bugs are more common in programs that do lots of manual pointer handling, which is why I recommended using std::vector. There could be a hidden bug in your Board (or Player, or other classes) that didn't cause problems in console mode. However, adding the GUI dramatically changes your memory layout, which could bring out previously-hidden bugs.

    Do you have access to a Linux machine? If so, run your console app through "Valgrind":http://valgrind.org/ and see if it finds any issues.

    [quote author="ath001" date="1395440315"]Also, yes, constructor for board is called once and never deconstructed.[/quote]Just to clarify: Is that what you think is happening, or is that what your app output tells you? (Ideally, they should be the same thing. But they might not be).

    Also, what about the Board address -- does it change during one run? (See my previous post forhow to print the address)



  • I don't have a linux machine , i'm programming on macOS.

    The constructor is called once and the deconstructor print statement were never called.

    I printed the address from when the board is created in button 1, and then again once i clicked button 2, they have the same address.


  • Moderators

    [quote author="ath001" date="1395446699"]I don't have a linux machine , i'm programming on macOS.[/quote]I just learnt that Valgrind works on Mac too: http://valgrind.org/info/platforms.html Give it a try.

    [quote]The constructor is called once and the deconstructor print statement were never called.

    I printed the address from when the board is created in button 1, and then again once i clicked button 2, they have the same address. [/quote]As far as I can see, your MainWindow code is correct. I suspect the bug is in Board.



  • Okay, i install valgrind, and ran the console app through, it doesn't have any major failures and work as it should but i get a ton of these messages using :

    valgrind --leak-check=full -v ./your_program

    messages:
    ==32061== Invalid read of size 8
    ==32061== at 0x100014D99: RivalTowerTax::landOn(Player&) (in ./a.out)
    ==32061== by 0x100011E70: FreeParking::landOn(Player&) (in ./a.out)
    ==32061== by 0x100012B07: main (in ./a.out)
    ==32061== Address 0x104831520 is not stack'd, malloc'd or (recently) free'd

    LEAK SUMMARY:
    ==32084== definitely lost: 10,920 bytes in 56 blocks
    ==32084== indirectly lost: 5,584 bytes in 61 blocks
    ==32084== possibly lost: 4,829 bytes in 56 blocks
    ==32084== still reachable: 52,341 bytes in 278 blocks
    ==32084== suppressed: 0 bytes in 0 blocks
    ==32084== Reachable blocks (those to which a pointer was found) are not shown.
    ==32084== To see them, rerun with: --leak-check=full --show-reachable=yes
    ==32084==
    ==32084== ERROR SUMMARY: 1055 errors from 89 contexts (suppressed: 0 from 0)

    It looks pretty bad, the board runs as it should but this seems like an overwhelming amount of memory loss


  • Moderators

    You're making good progress. :)

    Your memory leaks aren't critical at this point -- it's only in kilobytes, so your system can endure it without any noticeable effects (but it should be fixed eventually).

    However, you should fix the error below ASAP:
    [quote author="ath001" date="1395460591"]messages:
    ==32061== Invalid read of size 8
    ==32061== at 0x100014D99: RivalTowerTax::landOn(Player&) (in ./a.out)
    ==32061== by 0x100011E70: FreeParking::landOn(Player&) (in ./a.out)
    ==32061== by 0x100012B07: main (in ./a.out)
    ==32061== Address 0x104831520 is not stack'd, malloc'd or (recently) free'd[/quote]See http://valgrind.org/docs/manual/mc-manual.html#mc-manual.badrw

    Your program is trying to do an illegal read, so it will get garbage data. If it does an illegal write, then you might end up with memory corruption. Errors like these can easily cause board->getPlayer()[ 0]->getName() to not return the correct values.

    Follow the "quick-start guide":http://valgrind.org/docs/manual/quick-start.html and see if you can get Valgrind to tell you exactly where in your source code the errors occur.



  • I mean its a good shot, but i believe theres is a hinge to overcome:

    ==32270== WARNING: Support on MacOS 10.8 is experimental and mostly broken.
    ==32270== WARNING: Expect incorrect results, assertions and crashes.
    ==32270== WARNING: In particular, Memcheck on 32-bit programs will fail to
    ==32270== WARNING: detect any errors associated with heap-allocated data.
    ==32270==

    It might not accurately represent my code at all.



  • Thanks for the help JKSH, I appreciate it, i converted it to vectors, and it worked like a charm.


  • Moderators

    Glad I could help :) Please edit your original post and add "[SOLVED]" to the title.

    All the best with your project!


  • Moderators

    Glad you got it working!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.