Qt深入浅出(三)Qt的内存管理机制

4 内存管理机制

  • 一般我们不直接用QWidget来实例化对象,用它的派生类来生成对象,main函数中一般不写太多代码,都是在派生类的构造函数中进行窗口的初始化、布局、设置、其子窗口设置等等。

例如:

main.cpp


#include <QApplication>
#include "widget.h"
int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    Widget widget;
    widget.show();
    return app.exec();
}

widget.h


    
    
  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3. #include <QWidget>
  4. class Widget : public QWidget
  5. {
  6. public:
  7.    Widget(QWidget *parent = 0); //继承QWidget或者其派生类的时候,一般要实现带一个QWidget*参数的构造函数,用来指定其父窗口的对象。
  8. };
  9. #endif

widget.cpp


#include "widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent) : QWidget(parent)
{
    this->resize(400, 300);
    this->move(100, 100);
}

  • 构造函数中要用new来申请堆窗口对象,不能使用栈对象, 因为栈对象生命周期只在构造函数内,构造函数执行完成后,栈对象就被销毁了,于是看不到该窗口。

 以下是错误的写法:

扫描二维码关注公众号,回复: 10732122 查看本文章

#include "widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent) : QWidget(parent)
{
    this->resize(400, 300);
    this->move(100, 100);
    QPushButton pb;
    pb.setParent(this);
}

以下是正确写法:


    
    
  1. #include "widget.h"
  2. #include <QPushButton>
  3. Widget::Widget(QWidget *parent) : QWidget(parent)
  4. {
  5.    this->resize(400, 300);
  6. this->move(100, 100);
  7. QPushButton pb* = new QPushButton;
  8. pb->setParent(this);
  9. }

  • 我们看到以上正确代码只有new而没有delete,难道是课件代码写错了?我是否还要在析构函数里delete呢?

    ​ 其实是Qt有一套回收内存的机制,子窗口可以通过指定父窗口,来托管子窗口内存的释放,而父窗口又通过它的父窗口来销毁对象,顶级窗口一般在main函数中实例化为可自动销毁的栈对象,子窗口无需进行额外的释放。

    ​ 我们可以通过派生一个子窗口类,然后分别在父子窗口析构函数里打印信息,来观察子窗口的释放过程。

  • 是不是只有窗口类对象有这套管理机制,还是所有的Qt类都可以使用这套管理机制?

    ​ 所有的QObject派生类都可以通过指定父对象进行内存托管,QWidget继承至QObject,所以它能使用这套管理机制,后面我们还会接触到其它的QObject派生类对象,例如QGraphicsItem,它也可以使用这套内存管理机制。

  • 那么所有的子对象只能在父对象销毁的时候才能一起销毁,势必造成内存持续占用,能不能我们自己来销毁呢?

    ​ 当然,开发者可以使用delete来释放QObject对象,但是不推荐这么使用,QObject对象远比普通的类要复杂的多,QObject底层实现在我们不知道的情况下,正进行着一些工作。如果这个时候使用delete强制释放,会造成不可预知的错误。

    ​ 一般我们会使用deleteLater函数,进行安全释放,它会等待对象所有事情都处理完毕后才释放。

    
          
          
    1. [slot] void QObject::deleteLater();

发布了207 篇原创文章 · 获赞 66 · 访问量 20万+

4 内存管理机制

  • 一般我们不直接用QWidget来实例化对象,用它的派生类来生成对象,main函数中一般不写太多代码,都是在派生类的构造函数中进行窗口的初始化、布局、设置、其子窗口设置等等。

例如:

main.cpp


#include <QApplication>
#include "widget.h"
int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    Widget widget;
    widget.show();
    return app.exec();
}

widget.h


  
  
  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3. #include <QWidget>
  4. class Widget : public QWidget
  5. {
  6. public:
  7.    Widget(QWidget *parent = 0); //继承QWidget或者其派生类的时候,一般要实现带一个QWidget*参数的构造函数,用来指定其父窗口的对象。
  8. };
  9. #endif

widget.cpp


#include "widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent) : QWidget(parent)
{
    this->resize(400, 300);
    this->move(100, 100);
}

  • 构造函数中要用new来申请堆窗口对象,不能使用栈对象, 因为栈对象生命周期只在构造函数内,构造函数执行完成后,栈对象就被销毁了,于是看不到该窗口。

 以下是错误的写法:


#include "widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent) : QWidget(parent)
{
    this->resize(400, 300);
    this->move(100, 100);
    QPushButton pb;
    pb.setParent(this);
}

以下是正确写法:


  
  
  1. #include "widget.h"
  2. #include <QPushButton>
  3. Widget::Widget(QWidget *parent) : QWidget(parent)
  4. {
  5.    this->resize(400, 300);
  6. this->move(100, 100);
  7. QPushButton pb* = new QPushButton;
  8. pb->setParent(this);
  9. }

  • 我们看到以上正确代码只有new而没有delete,难道是课件代码写错了?我是否还要在析构函数里delete呢?

    ​ 其实是Qt有一套回收内存的机制,子窗口可以通过指定父窗口,来托管子窗口内存的释放,而父窗口又通过它的父窗口来销毁对象,顶级窗口一般在main函数中实例化为可自动销毁的栈对象,子窗口无需进行额外的释放。

    ​ 我们可以通过派生一个子窗口类,然后分别在父子窗口析构函数里打印信息,来观察子窗口的释放过程。

  • 是不是只有窗口类对象有这套管理机制,还是所有的Qt类都可以使用这套管理机制?

    ​ 所有的QObject派生类都可以通过指定父对象进行内存托管,QWidget继承至QObject,所以它能使用这套管理机制,后面我们还会接触到其它的QObject派生类对象,例如QGraphicsItem,它也可以使用这套内存管理机制。

  • 那么所有的子对象只能在父对象销毁的时候才能一起销毁,势必造成内存持续占用,能不能我们自己来销毁呢?

    ​ 当然,开发者可以使用delete来释放QObject对象,但是不推荐这么使用,QObject对象远比普通的类要复杂的多,QObject底层实现在我们不知道的情况下,正进行着一些工作。如果这个时候使用delete强制释放,会造成不可预知的错误。

    ​ 一般我们会使用deleteLater函数,进行安全释放,它会等待对象所有事情都处理完毕后才释放。

    
        
        
    1. [slot] void QObject::deleteLater();

猜你喜欢

转载自blog.csdn.net/qq_38025219/article/details/104829466