Qt中关于delete的应用

前言

这学期开了专业课Qt,第一次接触到C++,在C++中学习过程中,我们都知道:

delete 和 new 必须 配对使用(一 一对应):delete少了,则内存泄露,多了麻烦更大。
Qt作为C++的库,显然是不会违背C++的前述原则的。可是:

在Qt中,我们很多时候都疯狂地用new,却很少用delete,缺少的 delete 去哪儿了?!
本文整理了C++中关于delete和new的知识点。

Qt半自动的内存管理

在Qt中,以下情况下你new出的对象你可以不用 亲自去delete (但你应该清楚delete在何处被Qt调用的,怎么被调用的):

QObject及其派生类的对象,如果其parent非0,那么其parent析构时会析构该对象(本文内容围绕这一点展开 )
除此之外,有些类的对象可以接收设置一些特别的标记,比如:

QWidget及其派生类的对象,可以设置 Qt::WA_DeleteOnClose 标志位(当close时会析构该对象)
QAbstractAnimation派生类的对象,可以设置 QAbstractAnimation::DeleteWhenStopped
QRunnable::setAutoDelete()
MediaSource::setAutoDelete()

注意:这些用法会有些陷阱 ,请注意看本文最后的3个小例子。

在Qt中,最基础和核心的类是:QObject 。它的魔力很大,本文只关注两点:

  1. 父子关系
  2. deleteLater

父子关系

在Qt中,每个 QObject 内部都有一个list,用来保存所有的 children,还有一个指针,保存自己的parent。当它自己析构时,它会将自己从parent的列表中删除,并且析构掉所有的children。

注意:在 Qt 中,我们经常会遇到

  1. 基类、派生类,或父类、子类。 这是对于派生体系来说的,和在C++相关书中看到的完全一样,与这的parent无关
  2. 父对象、子对象、父子关系。 这是Qt中所特有的,也就是这儿的parent所引入的,与类的继承关系无关

建立与解除

Q_INVOKABLE QObject::QObject ( QObject * parent = 0 )

创建一个QObject对象时,如果指定了父对象,它就会将自己添加到父对象的 children 列表中

QObject::~QObject () [virtual]

当一个QObject对象析构时,它会将自己从父对象的 children 列表中移除(parent非0的话)

void QObject::setParent ( QObject * parent )

通过该函数,将自己从原父对象的children中删除,添加到新parent的children列表中

注:这三个函数都是通过一个内部私有函数来实现的,这就是
QObjectPrivate::setParent_helper(QObject *o)

获取父、子对象

每个QObject只有一个父对象:

QObject * QObject::parent () const
子对象可以有多个

const QObjectList & QObject::children () const
所以可以根据条件来查找喽:

T QObject::findChild ( const QString & name = QString() ) const
QList QObject::findChildren ( const QString & name = QString() ) const

关于delete的示例程序

  1. 普通释放(使用delete)和依靠父对象
#include "mainwindow.h"
#include <QApplication>
#include <QtWidgets>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QWidget * widget = new QWidget();
    widget->setWindowTitle(QObject::tr("我是widget"));

    QLabel * label = new QLabel();
    label->setWindowTitle(QObject::tr("我是label"));
    label->setText(QObject::tr("我是个窗口"));
    label->resize(180,20);

    QLabel * label2 = new QLabel(widget);
    label2->setText(QObject::tr("我不是独立窗口,只是widget的子部件"));
    label2->resize(250,20);

    label->show();
    widget->show();
    int ret = a.exec();
    delete label;              // 释放内存,因为label没有父对象,所以它的释放只能自己来。
    delete widget;             // label2有父对象,它依靠父对象释放,不用再单独对其释放
    return ret;
}

  1. 使用标志位
    ----使用标志位可以不显示的使用delete,但和使用delete是一样的。因为Qt在暗中
    使用了delete。
#include <QApplication>
#include <QLabel>


int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    QLabel *label = new QLabel;
    label->setAttribute(Qt::WA_DeleteOnClose);
    label->setText("first line\nsecond line");
    label->show();
    
    return app.exec();
}

----下面是一个暗中使用delete的例子。这是一个类,它有一个成员函数,可以删除
自己。当然只能删除由关键字new创建的自己。

#include<iostream>
using namespace std;

//类AAA
class AAA
{
public:
    //构造函数
    AAA();
    ~AAA(void);


    void delete_me(void);
};

//构造函数
AAA::AAA(void)
{
    //空的
}

//析构函数
AAA::~AAA(void)
{
    //空的
}

//删除自己
void AAA::delete_me(void)
{
    delete this;
}

//主函数
int main(void)
{
    AAA *a = new AAA;

    cout<<"point a will be deleted by himself."<<endl;
    a->delete_me();
    cout<<"point a has been deleted."<<endl;
    
    return 0;
}

参考和引用

  1. https://blog.csdn.net/zanilia123/article/details/54598697
  2. https://www.cnblogs.com/liushui-sky/p/5851936.html#t4

猜你喜欢

转载自blog.csdn.net/qq_41684134/article/details/87929039