Solved Unable to add items when function called from other class?
-
I have a function that adds some items to a ListWidget (filenames link to the source code in my GitHub repo):
void Debugger::addRegisterViewItem() { for (int i = 0; i < 16; i++) { ui->leftRegisterListWidget->addItem(QString("%1").arg(chip8->V[i], 4, 16, QChar{'0'}).toUpper()); } }
when I call this from within the Debugger class it works as expected. However, when I try calling it from another class:
void SDL2Widget::mainLoop() { // snip debug->updateWidgets(); // snip }
the program panics with a segmentation fault, and upon inspection, the
ui
pointer in the Debugger class is empty when called fromSDL2Widget.cpp
.I feel like I just have a fundamental lack of knowledge of how classes interact, but I'm not even sure where to look to learn how I should be doing it... I'm sorry for this probably very beginner question, but if someone could point me in the right direction I would be very grateful. :)
-
@adalovegirls said in Unable to add items when function called from other class?:
debug
Make sure this is a valid pointer.
-
@Christian-Ehrlicher Ahhh... I hadn't realized
getDebugContext()
was getting called before the Debugger window was actually created. I moveddebug = Debugger::getDebugContext();
intomainLoop
to test it, and it works. The thing I'm not sure to do, is how could I make suregetDebugContext()
is called after the Debugger window is created and shown? I have a feeling reassigning it in every iteration of the loop isn't the best practice. -
First you can use QPointer<QWidget> instead Widget* for your 'debug' member - then you will see if it's still valid when you call SDL2Widget::mainLoop()
-
@Christian-Ehrlicher How can I do that exactly? I changed the definition to
QPointer<QWidget> debug;
and it gives the errorimplicit instantiation of undefined template 'QPointer<QWidget>'
Thank you for the help so far!
-
First you should not use QWidget but your derived class (so 'Debugger' in your case) and than you should also include <QPointer>
-
@Christian-Ehrlicher Oh. It wasn't indicating I was missing
QPointer
but including it fixed it, along with the change fromQWidget
toDebugger
. After doing that however, the pointer is null when the time comes to callupdateWidgets()
. -
So my assumption is correct - the pointer is invalid and therefore the app is crashing.
-
@Christian-Ehrlicher How can I make it valid when I need it, then?
-
@adalovegirls said in Unable to add items when function called from other class?:
How can I make it valid when I need it, then?
I don't know your code - make sure to create a proper widget, don't delete it afterwards.
-
@adalovegirls said in Unable to add items when function called from other class?:
How can I make it valid when I need it, then?
Out of curiosity, is there a reason that everybody and their mother is a global variable?
Anyway, I peeked, and you're almost certainly callingupdateWidgets()
when there's noDebugger
object created.
Piece of advice - fix this code pronto. Globals are nasty, everything global is everything nasty ... you get the idea ... -
@kshegunov No reason! I'm just a beginner who doesn't really know what they're doing. :)
And yes, I am aware now that I was callingupdateWidgets()
whenDebugger
had yet to be created, I'm asking how I can solve this in a more elegant way than calling it every mainLoop iteration:void SDL2Widget::mainLoop() { debug = Debugger::getDebugContext(); if (debug) debug->updateWidgets(); }
It works, but I'm sure it's not the best way to do it.
-
@adalovegirls said in Unable to add items when function called from other class?:
And yes, I am aware now that I was calling updateWidgets() when Debugger had yet to be created, I'm asking how I can solve this in a more elegant way than calling it every mainLoop iteration:
If you keep the Debugger as a pseudo-singleton (i.e. a glorified global), this is exactly how you do it.
Alternatively, you can enforce that a debugger is created before whatever widget by passing its address through the widget's constructor (and saving it in a member variable). Then you can't create a widget without first having a debugger and you don't get/check anything in the loop. If you're in the loop thenDebugger
has been passed to you/exists already. -
@kshegunov Alright. I guess I'll stick with the current method then, because I don't want it to be a requirement that the debugger is created before the emulator runs.
-
@adalovegirls said in Unable to add items when function called from other class?:
Alright. I guess I'll stick with the current method then, because I don't want it to be a requirement that the debugger is created before the emulator runs.
Then I suggest you put the pointer into the class and set it to the widget through a setter, instead of coupling the classes through the
Debugger::getDebugContext
or pass it through the constructor, but with a default value (ofnullptr
). As a rule of thumb you want to rely on as few application-global states (a.k.a. global variables) as possible. -
@kshegunov I don't know how to do that without an example...
-
-
This post is deleted! -
@kshegunov Alright. I tried making a setter function in SDL2Widget, but in the header for it I'm getting the error
Debugger has not been declared
even though I have debugger.h included:SDL2Widget.h
#ifndef SDL2WIDGET_H #define SDL2WIDGET_H #include "chip8.h" #include "SDL.h" #include "debugger.h" #include <QDebug> #include <QWidget> #include <QTimer> #include <vector> class SDL2Widget : public QWidget { Q_OBJECT public: SDL2Widget(QWidget* parent = nullptr); ~SDL2Widget(); static void loadRom(std::vector<unsigned char> rom); static void recKey(int key, bool state); static Chip8* getC8Context(); static SDL2Widget* getSDLContext(); void setDebugContext(Debugger* dbg); }; #endif
SDL2Widget.cpp
void SDL2Widget::setDebugContext(Debugger* dbg) { debug = dbg; }
I'm also getting the error
no matching function for call to SDL2Widget::setDebugContext(Debugger*)
when calling the setter from the Debugger class:debugger.cpp
sdl2->setDebugContext(this);
-
You probably have a cyclic dependency. Forward declare the class(es) and include the headers in the source files only is the solution.