精华内容
下载资源
问答
  • QT内存管理

    2021-01-12 12:48:56
    QT内存管理QObjectQT半自动化的内存管理方式一:方式二:方式三:方式四: QObject QObject是 QT最基础和核心的类。其内部有一个list,会保存children,还有一个指针保存parent,当自己析构时,会自己从parent列表中...

    QObject

    QObject是 QT最基础和核心的类。其内部有一个list,会保存children,还有一个指针保存parent,当自己析构时,会自己从parent列表中删除并且析构所有的children。
    QT对象之间可以存在父子关系,每一个对象都可以保存它所有子对象的指针,每一个对象都有一个指向其父对象的指针。

    注:子界面的parent并不一定是构造子界面时的参数parent;如下

    #include <QtWidgets/QWidget>
    #include <QWizard> 
    #include <QDebug> 
    
    class WizardPage : public QWizardPage
    {
    	Q_OBJECT
    public:
    	WizardPage(QWizard* parent = Q_NULLPTR) :QWizardPage(parent)
    	{
    	}
    	~WizardPage() = default;
    };
    
    class Wizard : public QWizard
    {
    	Q_OBJECT
    
    public:
    	Wizard(QWidget* parent = Q_NULLPTR) :QWizard(parent)
    	{
    		mPage = new WizardPage(this);
    		addPage(mPage);
    
    		if (this== mPage->parent()->parent()->parent())
    		{
    			qDebug() << true;
    			//在构造mPage参数传的是this,但是 mPage->parent()->parent()->parent()才是this
    		}
    	}
    	~Wizard()
    	{
    		delete mPage;
    	}
    
    private:
    	WizardPage* mPage = nullptr;
    };
    

    QT半自动化的内存管理

    方式一:

    QObject及其派生类的对象,如果其parent非0,那么其parent析构时会析构该对象。
    注:如果父对象和子对象都分配在栈上,并且先释放父对象的内存空间,释放父对象的时候子对象的空间将会被释放,再释放子对象的空间时,因为子对象空间已经被释放,会发生内存错误。如:

    class Lable:public QLabel
    {
    public:
     Lable(QWidget* parent = nullptr) :QLabel(parent)
     {}
     
     ~Lable()
     {
         qDebug() << "~Lable";
     }
    };
    
    class Widget :public QWidget
    {
    public:
     Widget(QWidget* parent = Q_NULLPTR):QWidget(parent)
     {}
    
     ~Widget()
     {
         qDebug() << "~Widget";
     }
     
    };
    
    
    int main(int argc, char* argv[])
    {
     QApplication a(argc, argv);
     Lable lable;
     Widget widget;
     lable.setParent(&widget);
     widget.show();
     return a.exec();
    }
    

    处理方式:
    1、调整父子对象的顺序。即:

    int main(int argc, char* argv[])
    {
     QApplication a(argc, argv);
     
     Widget widget;
     Lable lable;
     lable.setParent(&widget);
     widget.show();
     
     return a.exec();
    }
    

    2、在堆上构造对象。即:

    int main(int argc, char* argv[])
    {
     QApplication a(argc, argv);
     
     Lable* lable = new Lable();
     Widget* widget = new Widget();
     lable->setParent(widget);
     widget->show();
     delete widget;
    
     return a.exec();
    }
    

    方式二:

    QWidget及其派生类的对象,可以设置 Qt::WA_DeleteOnClose 标志位(当close时会触发该对象的析构函数)。

    int main(int argc, char* argv[])
    {
        QApplication a(argc, argv);
    
        Lable* lable = new Lable();
        Widget* widget = new Widget();
        widget->setAttribute(Qt::WA_DeleteOnClose);
        lable->setParent(widget);
        widget->show();
    
        return a.exec();
    }
    

    其它内存管理方式

    方式一:

    RAII技术。适用于C++。

    class MyWidget
    {
    public:
        MyWidget(QWidget* parent = Q_NULLPTR):mWidget(new QWidget(parent))
        { }
    
        ~MyWidget()
        {
            delete mWidget;
            qDebug() << "~MyWidget";
        }
    
        void show()
        {
            mWidget->show();
        }
        
    private:
        QWidget* mWidget = nullptr;
    };
    
    int main(int argc, char* argv[])
    {
        QApplication a(argc, argv);
    
        MyWidget widget;
        widget.show();
        
        return a.exec();
    }
    

    方式二:

    智能指针。
    QT提供多种智能指针。
    QScopedPointer 同 std::unique_ptr,移动语义,所有权的转换;
    QSharedPointer 同 std::shared_ptr,引用计数的方式实现;
    QWeakPointer 同 std::weak_ptr,对std::shared_ptr的补充,出现循 环引用时std::shared_ptr无法正确的管理内存。

    展开全文
  • Qt内存管理(一) 半自动内存管理机制

    千次阅读 2018-07-18 09:12:52
    概述 看多了Qt的代码就会发现,很多人...原因在于Qt采用半自动的内存管理,不像c++那种全需要自己delete堆内存对象。Qt对象继承自QObject, QObject内部有一个list,会保存children,即QObjectList* children;还有...

    概述

    看多了Qt的代码就会发现,很多人的代码里大量使用new,却很少看到delete,以至于我刚学Qt时也养成了这个习惯,在写C++时也不用delete,结果造成很多麻烦。

    原因在于Qt采用半自动的内存管理,不像c++那种全需要自己delete堆内存对象。Qt对象继承自QObject, QObject内部有一个list,会保存children,即QObjectList* children;还有一个指针保存parent,即QObject *parent。当此Qt对象执行析构函数时,它会将自己从parent的列表中删除,并且析构掉所有的children。

    objParent有两个子对象objChildobjChild2,三者都继承自QObject,那么关系如下图:

    半自动化的内存管理规则

    1. QObject及其派生类的对象,如果其parent非0,那么其parent析构时会析构该对象。

    2. QWidget及其派生类的对象,可以设置Qt::WA_DeleteOnClose标志位,当close时会调用QWidgetPrivate::close_helper,进而调用deleteLater析构该对象。

    3. QAbstractAnimation派生类的对象,可以设置QAbstractAnimation::DeleteWhenStopped

    4. QRunnable::setAutoDelete()MediaSource::setAutoDelete()

    5. 父子关系:Qt特有的性质,与类的继承关系不同,注意二者要在同一线程。

    使用如下:

    QObject *p = new QObject();
    
    MySon1 ps1(p);
    MySon2* ps2 = new MySon2();
    ps2->setParent(p);

    注意要求是对象而不是指针,如果是指针就要用setParent函数。代码MySon2* ps2 = new MySon2(p);是不能实现自动析构的,会内存泄漏。

    源码分析

    构造函数

    QObject构造函数部分代码:

    if (parent) {
        QT_TRY {
            if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData)  )
                parent = 0;
            if (d->isWidget) {
                if (parent) {
                    d->parent = parent;
                    d->parent->d_func()->children.append(this);
                }
                // no events sent here, this is done at the end of the QWidget constructor
            } else {
                setParent(parent);
            }
        }
        ......

    如果指定了parent,那么先判断parent和当前对象是否在同一线程,如果不在就令parent=0,如果当前对象是widget且存在parent(在同一线程),那么赋给parent指针,而且后者添加本对象到子对象的QList,在QWidget构造函数最后发送事件QEvent::ChildAdded
    如果当前对象不是widget就调用setParnet,又调用了QObjectPrivate::setParent_helper

    void QObjectPrivate::setParent_helper(QObject *o)
    {
        Q_Q(QObject);
        if (o == parent)
            return;
        if (parent) {
            ......
        }
        parent = o;
        if (parent) {
            ......
            }
    }

    这个函数的源码太长,大致还是对两个指针做了类似的操作,最后同步向事件循环发送了QEvent::ChildAdded事件。
    注意这里的parent是QObjectData的成员变量,也就是父指针parent。

    析构函数

    QObject析构函数大致如下:

    QObject::~QObject()
    {
        Q_D(QObject);
        d->wasDeleted = true;
        d->blockSig = 0; // unblock signals so we always emit destroyed()
        ......
        if (!d->isWidget && d->isSignalConnected(0)) {
            emit destroyed(this);   // 发射destroyed信号,且无法blocked,一般情况下没有槽来响应
        }
        ......
        if (d->connectionLists || d->senders) {
            ......
            /* disconnect all receivers  Disconnect all senders */
        }
        // 析构掉所有的children
        if (!d->children.isEmpty())
            d->deleteChildren();
    
    #if QT_VERSION < 0x60000
        qt_removeObject(this);
    #endif
    
        if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
            reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(this);
        if (d->parent)        // remove it from parent object,将自己从parent的列表中删除
            d->setParent_helper(0);
    }

    其中deleteChildren代码如下:

    void QObjectPrivate::deleteChildren()
    {
        Q_ASSERT_X(!isDeletingChildren, "QObjectPrivate::deleteChildren()", "isDeletingChildren already set, did this function recurse?");
        isDeletingChildren = true;
        // delete children objects, don't use qDeleteAll as the destructor of the child might delete siblings
        for (int i = 0; i < children.count(); ++i) {
            currentChildBeingDeleted = children.at(i);
            children[i] = 0;
            delete currentChildBeingDeleted;    //删除子对象
        }
        children.clear();
        currentChildBeingDeleted = 0;
        isDeletingChildren = false;
    }

    函数清除所有子类指针,当然每个子类指针清除时又会清除它的所有子类,因此Qt中new出来的指针很少有显示对应的delete,因为只要最上面的指针被框架删除了,以前版本的源码用的是qDeleteAll,而且直接放在QObject析构函数里。

    setParent_helper实际执行的代码如下:

    QObjectPrivate::setParent_helper(QObject *o)
    {
        parentD->children.removeAt(index);
        if (sendChildEvents && parentD->receiveChildEvents) {
            QChildEvent e(QEvent::ChildRemoved, q);
            QCoreApplication::sendEvent(parent, &e);
        }
    }

    向事件循环发送了事件QEvent::ChildRemoved,再看事件循环部分的源码:

    bool QObject::event(QEvent *e)
    {
        switch (e->type()) {
        ......
        case QEvent::ChildRemoved:
            childEvent((QChildEvent*)e);
            break;
        }
    }
    //虚函数
    void QObject::childEvent(QChildEvent * /* event */)
    {
    }

    Qt内存管理机制的缺陷

    Qt半自动内存机制的缺陷在于parent不区分它的child是分配在stack上还是heap上,结果会出现parent析构stack上的子对象。因此,Qt对象析构的核心原则是保证子对象先析构,这样它会把自己从父对象列表中删除,二者取消关联,那么父对象析构时就不会再次析构子对象了。

    看这样的代码:

    QApplication app(argc, argv);
    QLabel label("Hello Qt!");
    QWidget w;
    label.setParent(&w);
    w.show();
    return app.exec();

    C++规定,本地对象的析构函数的调用顺序与他们的构造顺序相反。所以是QWidget对象先析构,也就是父对象先析构,它会删除子对象label,但label却不是通过new分配在heap中,而是在stack中,当然会出问题。运行之后正常,但关闭窗口会报错:

    改进方法一:只要把QLabel和QWidget的构造语句交换一下就可以了,这也是一般人的代码习惯。

    改进方法二:让QLabel对象创建在heap上:

    QLabel *label = new QLabel("Hello Qt!");
    QWidget w;
    label->setParent(&w);
    展开全文
  • qt内存管理 和回收的各种方式,例子简单明了。 还有比较详细的注释, 明白这些小例子 对于你理解qt的垃圾回收机制有不小的帮助。
  • 其实这两块内容吧,还是很重要的,但是由于这两块网上也已经有很多文章了,而且写得灰常好了,自己在这里也就不多废话了。dbzhang800对于事件循环...Qt Event Dispatcher: http://blog.csdn.net/dbzhang800/article/d

         其实这两块内容,还是很重要的,但是由于这两块网上也已经有很多文章了,而且写得灰常好了,自己在这里也就不多废话了。dbzhang800对于事件循环的这些博文,个人认为写的是非常好的,估计我来写也就是把这些内容整理整理再发表一下。这里直接贴上来,有兴趣的可以移步过去看一下。
    Qt Event Dispatcher:
    http://blog.csdn.net/dbzhang800/article/details/6882981
    Qt事件循环嵌套:
    http://blog.csdn.net/dbzhang800/article/details/6889291
    QEvent 子类化一例:
    http://blog.csdn.net/dbzhang800/article/details/6642462
    QEventLoop使用两例:
    http://blog.csdn.net/dbzhang800/article/details/6300519
    Qt源码学习(从Win32到Qt):
    http://blog.csdn.net/dbzhang800/article/details/6370300
    从 Qt 的 delete 说开来:
    http://blog.csdn.net/dbzhang800/article/details/6300025
    漫谈QWidget及其派生类系列开篇:
    http://blog.csdn.net/dbzhang800/article/details/6737540
    (注:好像是在这篇系列中有这么一个结论:QWidget的实际初始化是在show的时候才会去做,这样我们往往在构造函数中去取size是无效的。很有用,忘记出点在哪里了。应该在这个系列中)

    Qt内存管理:
    上面的“从 Qt 的 delete 说开来:”也算。
    http://devbean.blog.51cto.com/448512/526734/
    http://www.cnblogs.com/wucg/p/3878611.html

    Windows系统内存管理方面的文章:
    http://blog.csdn.net/yeming81/article/details/2046193

    关于事件的封装过程也许会另外开篇再讲一次。

    展开全文
  • Qt内存管理更偏向于Java这种自动GC的机制,例如从QObject类派生的类,且指定了父类,这种对象内存自动回收。 例如,我们写一个按钮类MyButton, 继承于QPushButton,在QtCreator中添加类时,没有QPushButton, ...

            在做界面开发时,Qt相对于MFC方便了很多,各种对象方法的封装更加适合程序员调用。Qt的内存管理更偏向于Java这种自动GC的机制,例如从QObject类派生的类,且指定了父类,这种对象内存自动回收。

            例如,我们写一个按钮类MyButton, 继承于QPushButton,在QtCreator中添加类时,没有QPushButton, 选择QWidget, 我们在代码做修改即可。

           MyButton.h文件

    #ifndef MYBUTTON_H
    #define MYBUTTON_H
    
    #include <QPushButton>
    
    class MyButton : public QPushButton
    {
        Q_OBJECT
    public:
        explicit MyButton(QWidget *parent = nullptr);
    
        //加上析构函数
        ~MyButton();
    
    signals:
    
    public slots:
    };
    
    #endif // MYBUTTON_H
    

        MyButton.cpp文件

    #include "mybutton.h"
    #include <QDebug>
    
    MyButton::MyButton(QWidget *parent) : QPushButton(parent)
    {
    
    }
    
    MyButton::~MyButton()
    {
        qDebug() << "run ~MyButton()";
    }
    

        在主程序文件中调用

    #include "mainwindow.
    展开全文
  • Qt 内存管理

    千次阅读 2013-11-16 18:58:12
    delete 和 new 必须 配对使用(一 一对应):delete少了,则内存泄露,多了麻烦更大。 Qt作为C++的库,显然是不会违背C++的前述原则的。可是: 在Qt中,我们很多时候都疯狂地用new,却很少用delete,缺少的 ...
  • Qt内存管理

    2014-02-26 11:03:11
    Qt的程序中经常会看到只有new而不delete的情况,其实是因为Qt有一套回收内存的机制,主要的规则如下: 1.所有继承自QObject类的类,如果在new的时候指定了父亲,那么它的清理时在父亲被delete的时候delete的,...
  • Qt平台下C++内存管理

    2020-04-11 14:53:55
    C++编程中,内存一直就是显著的问题。在Qt平台中,我推荐使用Qt智能指针、对象树、大内存技术来进行内存管理
  • Qt 内存管理机制

    2021-11-17 09:23:16
    添加链接描述
  • Qt内存管理(五) 自动垃圾回收机制

    千次阅读 2018-07-18 09:15:49
    实现自动垃圾回收的工具主要是Qt对象清理器,也就是QObjectCleanupHandler类,它监视多个QObject对象的生命期。当你想知道被别人拥有的QObject对象是否被删除时,这个类就派上了用场。例如引用(referencing memory)...
  • Qt内存管理(三) Qt的智能指针

    千次阅读 2018-07-18 09:14:31
    Qt常用的智能指针有QPointer,QScopedPointer,QSharedPointer。 关于这几个智能指针,网上的博客基本不是翻译Qt文档,就是翻译老外的博客,比较失望。 QPointer QPointer属于Qt对象模型的特性,本质是一个模板类...
  • Qt内存管理(四) deleteLater

    千次阅读 2018-07-18 09:15:07
    代替比较好,它会让所有事件都发送完一切处理好后马上清除这片内存,而且就算调用多次的deletelater也是安全的。 结合第一篇和本篇,可以明白为什么Qt的代码里很少有直接用 delete 的场合了。 参考: How ...
  • Qt内存管理(二) qDeleteAll与clear

    千次阅读 2018-07-18 09:13:36
    qDeleteAll:专门用于指针容器,对容器或者迭代器中的每个对象进行 delete ...qDeleteAll可以释放容器元素内存,但没有对容器的置空操作,也就是size没变。所以 qDeleteAll之后必须加上clear方法 。
  • Qt 内存管理与布局管理器

    千次阅读 2012-08-02 22:57:13
    在网上搜索得知:Qt完善了C++的内存管理机制,“如果指针对象有父对象,那么父对象在被释放时,会自动释放子对象”。所以我在练习时,创建的控件都传递了this指针,作为其父对象。 但是,当我在练习布局管理器的...
  • Qt深入浅出(三)Qt内存管理机制

    千次阅读 2018-02-24 00:16:34
    4 内存管理机制一般我们不直接用QWidget来实例化对象,用它的派生类来生成对象,main函数中一般不写太多代码,都是在派生类的构造函数中进行窗口的初始化、布局、设置、其子窗口设置等等。例如:main.cpp #include &...
  • 30.Qt内存管理

    2021-01-19 14:37:09
    关于Qt中new对象的管理 1 创建对象时,继承父类,由父类销毁时候,自动销售子类 如 QWidget * w = new QWidget(this); 2 通过设置类的属性,当界面关闭时,自动销毁 NudtPlan * plan = new NudtPlan; connect...
  • Qt为软件开发人员提供了一套内存管理机制,用以替代手动内存管理。 下面开始逐条讲述Qt中的内存管理机制。 一脉相承的栈与堆的内存管理 了解C语言的同学都知道,C语言中的内存分配有两种形式:栈内存、堆内存。 栈...
  • 当我们在使用Qt时不可避免得需要接触到内存的分配和使用,即使是在使用Python,Golang这种带有自动垃圾回收器(GC)的语言时我们仍然需要对Qt内存管理机制有所了解。 在Qt中,我们可以大致把对象分为两类,一类是...
  • QT中的继承关系 day1优化   一般我们不直接用QWidget来实例化对象,用它的派生类来生成对象,main函数中一般不写太多代码,都是在派生类的构造函数中进行窗口的初始化、布局、设置、其子... } QT内存管理机制 例:
  • Qt作为第三方类库,给出了一套很好的内存管理机制。 首先需要明确一个概念,Qt作为一套GUI(图形用户界面)类库,在开发时,我们应用最多的就是各类窗口,其中经常用到父子窗口。必须明确,父子窗口一种窗口之...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,937
精华内容 7,974
关键字:

qt内存管理