【问题标题】:What is the delete sequence of QObject with default parent in Qt?Qt中具有默认父级的QObject的删除顺序是什么?
【发布时间】:2014-12-17 05:04:32
【问题描述】:

Qt 文档说如果一个 QObject 有一个父对象,那么当父对象被删除时,它也会删除它的所有子对象。 但是,如果我有多个具有默认父级 (0) 的 QObject,它们何时会被删除? 删除的顺序是什么?

【问题讨论】:

    标签: qt qobject


    【解决方案1】:

    如果我们谈论的是指向QObject 的指针,不,它们不会被删除。除非您手动删除它们,否则您将有内存泄漏,因此不会有任何删除顺序。

    除非在指针上调用delete,否则指针不会释放它们的内存。假设您有一个指向没有其他指针指向的内存位置的指针。如果该指针超出范围并且您没有对其调用 delete,您将拥有 memory leak,因为如果没有其他指针指向该内存位置,那么您将无法再访问该内存位置。你会得到一块无法访问且无用的内存。

    在类中,析构函数的目的是在删除时释放内存。当类的实例超出范围时调用析构函数(如果实例分配在堆栈上 ie 静态,eg MyClass x;)或调用它们的 delete (如果指针 ie 是动态的,eg MyClass *x = new MyClass;

    Qt 创造了一个聪明的机制,这样程序员就不必考虑太多这些事情,因为很多错误都是因为它们而发生的。所以Qt 介绍了父母,如果您将QObject 设置为父母,那么当您删除父母时,QObject 也会被删除。

    如果您使用QObject 指针作为类中的成员并且不将它们设置为父级,则当该类的实例被删除时,您将发生内存泄漏,当然,除非您在析构函数中手动删除它们.

    例如,如果使用以下实现会造成内存泄漏:

    class MyObject : public QObject
    {
    public:
        MyObject(QObject *parent = 0);
        ~MyObject();
    
    private:
        QTimer *m_pTimer;
    }
    
    MyObject::MyObject(QObject *parent) : QObject(parent)
    {
        m_pTimer = new QTimer; // memory leak when this will be destroyed
    }
    
    MyObject::~MyObject()
    {
    }
    

    为了解决这个问题,您应该提供this 作为父母:

    MyObject::MyObject(QObject *parent) : QObject(parent)
    {
        m_pTimer = new QTimer(this);
    }
    

    MyObject::~MyObject()
    {
        delete m_pTimer;
    }
    

    在这样的实现中:

    class MyObject : public QObject
    {
    public:
        MyObject(QObject *parent = 0);
        ~MyObject();
    
    private:
        QTimer m_timer;
    }
    
    MyObject::MyObject(QObject *parent) : QObject(parent)
    {
        // Do stuff
    }
    
    MyObject::~MyObject()
    {
    }
    

    如果你没有在堆上分配指针和内存,当类的实例(在我们的例子中为MyObject)获取时,所有成员都会在超出范围时被销毁ie超出范围。

    我认为这里值得一提的是Qt 中的layouts system

    假设你有一个QWidget,里面有一个QPushButton。如果创建QLayout,将QPushButton添加到QLayout,并将QWidget上的QLayout设置为QWidget::setLayout,将自动在QPushButton和@987654347之间创建子父关系@ 以及 QLayoutQWidget 之间。

    这是一个例子:

    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit Widget(QWidget *parent = 0);
        ~Widget();
    
    private:
        QGridLayout *m_pLayout;
        QPushButton *m_pButton;
    };
    
    
    Widget::Widget(QWidget *parent) :
        QWidget(parent)
    {
        m_pLayout = new QGridLayout;
        m_pButton = new QPushButton;
        m_pButton->setText("Push me!");
    
        m_pLayout->addWidget(m_pButton, 0, 0);
    
        setLayout(m_pLayout); // In this moment *this* will be automatically 
                              // set as parent for both m_pLayout and m_pButton
                              // even though no parent was passed to their constructors.
    }
    
    Widget::~Widget()
    {
    }
    

    我希望这会有所帮助。

    【讨论】:

    • 在您使用new QTimer 的示例中,您有一个空的析构函数。您声明为了解决这个问题,您应该将其作为父母提供: code snippet empty desctructor。我想你想把delete timer; 放在那里。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-16
    • 1970-01-01
    • 1970-01-01
    • 2021-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多