PDA

View Full Version : Critical error detected c0000374 - on close MainWindow



andreaQt
21st October 2020, 19:32
When i try to test the code, the program do the job, only at quit (by pressing X on the MainWindow) i have this issue:
in the "Application Ouput" window is write the current message "Critical error detected c0000374" and the debugger enter in editobject.h file with the yellow arrow at line 6;
what wrong i do?

d_stranz
21st October 2020, 20:33
And did you ask Google what this error message means? This hit (https://www.reddit.com/r/cpp_questions/comments/9unky7/critical_error_detected_c0000374_what_am_i_doing/) seems like it might be particularly relevant. (Not the specific error the poster experienced, but what the error means). And no, it isn't a bug in Qt.

Hint: Look at how you have declared your QWidget-based variables in MainWindow.h. Why do all other Qt applications create child windows on the heap and not the stack (as your code does)? And how do you think that might result in memory corruption when your MainWindow is closed (and deleted)?

andreaQt
22nd October 2020, 11:09
I try to answer:
1a) In Qt app is better to create child window or object on the heap because on close window or delete parent object all childs are deleted.
1a) On the stack is better to store small size data object and with contest access (like functions or slots), in the heap large size data object and without constest access.
2a) Like i read "Whether or not the variables are on the heap or stack depends upon how the object is allocated. So all members of the class will be allocated how the object is allocated." in https://forum.qt.io/topic/108617/class-properties-in-stack-or-heap so: MainWindow is allocated on the stack, like in my code glWidgetWindow+built_sphere_window+built_cylinder_ window+and so on (from Mainwindow.h) are allocated on the stack, what it is happen is an overflow of the stack?
2b)I'm confused about:


MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
QLabel test_stack_label(tr("Stored in Stack")); // this label is stored in the stack like MainWindow
QLabel test_heap_label(tr("Stored in Heap")); // this label is stored in the heap or is stored in the stack like its parent MainWindow
}

d_stranz
22nd October 2020, 17:17
2b)I'm confused about:

OK, I will explain. The reason your code is crashing is because you have declared your member variable widgets directly, as QWidget instances, rather than as pointers to QWidget instances. Memory is being corrupted in the MainWindow destructor because the member variables are destroyed by C++ before the MainWindow instance is destroyed. However, because in Qt, these child widgets are owned by the MainWindow, Qt is trying to destroy them a second time (through the Qt parent-child relationship, which is responsible for destroying them), after C++ has already destroyed them. The memory they used to occupy is gone, and so you get a crash because Qt is trying to access an object that no longer exists. (It could be happening the other way around - Qt destroys them first, and then C++ tries to do it again, but it's the same effect).

This has nothing to do with arguments about whether it is better to use heap vs. stack in any particular situation. It is entirely about Qt's parent-child ownership hierarchy of QObjects and who is in charge of the child objects' lifetimes.

So the solution to your problem is pretty simple:

1. Change every one of your QWidget-based member variables in MainWindow to "QWidget *".
2. In the constructor for MainWindow, call the "new" operator to create the QWidget instances
3. Use these widgets through the pointer operator (->)



// MainWindow.h

// Change #1:
private:
GlWidget * glWidgetWindow;
BuiltSphere * built_sphere_window;
BuiltCylinder * built_cylinder_window;
EditObject * edit_object_window;

QComboBox * builder_select;
QStackedWidget * builder_stacked_widget;
QTabWidget * tab_widget_01;




// MainWindow.cpp:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
// Change #2:
glWidgetWindow = new GlWidget( this );
built_sphere_window = new BuiltSphere( this );
// etc.

// Change #3:
glWidgetWindow->setFixedSize( 1024, 768 );
// etc.


In general, you should never declare QWidget-based member variables as QWidget, but always as QWidget *. (Actually, anything QObject-based).

The only places you should use QWidget directly are these (and maybe a few other similar cases):

1. In a method where the QWidget is in scope only for the life of the method, such as posting a dialog to get information from the user.



void MainWindow::showTheDialog()
{
QDialog theDialog;
theDialog->exec();
}


2. For MainWindow in main.cpp:



int main( int argc, char * argv[] )
{
QApplication a( argc, argv );
MainWindow w;
w.show();
return a.exec();
}


In both of these cases, the QObject instances are completely contained within the scope of the method so it is safe to create them on the stack.