1

Could someone explain to me why I get a segmentation fault if, in the following code, I remove del app between each call to QApplication's constructor? Similarly, assigning QApplication objects to variables with different names (e.g. app_1, app_2, app_3) avoids the segmentation fault.

from PyQt5.QtWidgets import (QApplication, QMessageBox)
import sys

if __name__ == '__main__':
    app = QApplication(sys.argv)
    msg = QMessageBox()
    msg.setText('Message Box 1')
    msg.show()
    app.exit(app.exec())
    del app  # Why is this necessary to avoid a segmentation fault?

    app = QApplication(sys.argv)
    msg = QMessageBox()
    msg.setText('Message Box 2')
    msg.show()
    app.exit(app.exec())
    del app  # Why is this necessary to avoid a segmentation fault?

    app = QApplication(sys.argv)
    msg = QMessageBox()
    msg.setText('Message Box 3')
    msg.show()
    app.exit(app.exec())

Clarification: I am not interested in "fixing" this code. I am trying to understand the behavior.

1 Answer 1

4

The problem is more relative to C++ than Python.

The following should be considered:

  • QApplication is accessed by the entire application using the instance() method since it is a singleton.

  • When the exit() method is called, it does not eliminate the object just stop processing the events.

So when you create another QApplication without deleting the previous one, the instance is not created and therefore instance() is nullptr:

import sys
from PyQt5.QtWidgets import QApplication, QMessageBox

if __name__ == "__main__":
    app = QApplication(sys.argv)
    print(f"app: {app}, instance: {QApplication.instance()}")
    msg = QMessageBox()
    msg.setText("Message Box 1")
    msg.show()
    app.exit(app.exec())
    app = QApplication(sys.argv)
    print(f"app: {app}, instance: {QApplication.instance()}")

Output:

app: <PyQt5.QtWidgets.QApplication object at 0x7effbd41ea50>, instance: <PyQt5.QtWidgets.QApplication object at 0x7effbd41ea50>
app: <PyQt5.QtWidgets.QApplication object at 0x7effbd41eb90>, instance: None

So at the time of setting the text with setText() a signal is used that uses the eventloop through the QXApplication using the instance() method that as we see is nullptr generating the segmentation fault.

In the case of using other names for QXApplication the eventloop will access another instance() that will not be None (nullptr)

import sys
from PyQt5.QtWidgets import QApplication, QMessageBox

if __name__ == "__main__":
    app1 = QApplication(sys.argv)
    print(f"app: {app1}, instance: {QApplication.instance()}")
    msg = QMessageBox()
    msg.setText("Message Box 1")
    msg.show()
    app1.exit(app1.exec())
    app2 = QApplication(sys.argv)
    print(f"app: {app2}, instance: {QApplication.instance()}")
    msg = QMessageBox()
    msg.setText("Message Box 1")
    msg.show()
    app2.exit(app2.exec())

Output:

app: <PyQt5.QtWidgets.QApplication object at 0x7f3462720a50>, instance: <PyQt5.QtWidgets.QApplication object at 0x7f3462720a50>
app: <PyQt5.QtWidgets.QApplication object at 0x7f3462720b90>, instance: <PyQt5.QtWidgets.QApplication object at 0x7f3462720b90>

In conclusion if you do not use del then instance() it will be None, however if you use it it will be called the destructor of the object in C++ eliminating the memory returned by instance() and allowing to create a new object.


As @ekhumoro says:

It's the exact order of deletion that really matters. Without del, the new QApplication is created before the old one is deleted (so the old instance() doesn't get replaced). But then the app variable is immediately reassigned, which implictly deletes the old application, making instance() return None.

Sign up to request clarification or add additional context in comments.

2 Comments

It's the exact order of deletion that really matters. Without del, the new QApplication is created before the old one is deleted (so the old instance() doesn't get replaced). But then the app variable is immediately reassigned, which implictly deletes the old application, making instance() return None.
@ekhumoro That's what I try to say, I think your explanation is clearer so I will add it to my answer if you have no problems

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.