QT中的内存管理一个小经验

最近在看Qwt给的示例的源码,遇到这么一句代码:

dataCurve->setSymbol(new QwtSymbol(QwtSymbol::Ellipse, QBrush( Qt::red ), QPen( Qt::red ), QSize( 9, 9 )));
我在想,这样直接new 了一个指针出来作为实参,什么时候delete 掉的呢,难道不会发生内存泄露吗?

函数的原型如下:

void QwtPolarCurve::setSymbol	(QwtSymbol * symbol)	
难道在函数的内部最后会delete 掉,那么传入一个栈对象的地址,也就是一个栈对象的指针,如果存在delete,难道不是会发生错误吗?

于是有了下边的实验:

QwtSymbol symObj(QwtSymbol::Ellipse,QBrush( Qt::red ), QPen( Qt::red ), QSize( 9, 9 ) );
dataCurve->setSymbol(&symObj );

先在栈上构造一个对象,然后传入这个对象的地址;一编译,无错,运行也没有问题,但是在程序退出的过程中,会发生异常。说明的确需要传入一个堆上的地址才行。


这里插播一句,QT中的对象的拷贝构造函数和赋值构造函数都是private 的,这样

QwtSymbol symObj = QwtSymbol((QwtSymbol::Ellipse,QBrush( Qt::red ), QPen( Qt::red ), QSize( 9, 9 ) ));

QwtSymbol symObj(QwtSymbol((QwtSymbol::Ellipse,QBrush( Qt::red ), QPen( Qt::red ), QSize( 9, 9 ) )));
显然都是错误的。


回到正题,那问题是,申请的堆上的地址到底有没有释放掉呢?


下边进一步实验,这下传入一个堆上的地址,不过是一个具名的实参:

QwtSymbol* ptrSym =new QwtSymbol(QwtSymbol::Ellipse,QBrush( Qt::red ), QPen( Qt::red ), QSize( 9, 9 ));
dataCurve->setSymbol(ptrSym);
然后在语句块的结束处,手动释放分配的内存:

delete ptrSym;
结果一样,程序启动和运行都没有什么问题,但是在退出的过程中发生了异常,说明不需要去显示的释放。

那么也就是示例代码中,已经帮我们释放了。


进一步实验验证内存确实被释放了。如果delete 指向堆的指针,是会调用析构函数的,那就从从析构函数的调用与否来验证。

查看帮助文档,发现QwtSymbol类 的析构函数刚好为virtual 的,如果派生自QwtSymbol类,析构的时候刚好可以正确的调用派生类的析构函数。

在派生类的析构函数中打印输出,作为标记。其他的什么都添加,只是对QwtSymbol 类的一个简单包装。查看帮助文档,使用QwtSymbol 的一个构造函数的版本(就是示例代码中用来的那个),来设计派生类的构造函数,派生类的构造函数只需要在初始化列表中调用基类QwtSymbol 的构造函数即可,最终的设计如下:

class QMySymbol: public QwtSymbol
{
public:
    QMySymbol(	QwtSymbol::Style style,
                const QBrush & 	brush,
                const QPen & 	pen,
                const QSize & 	size
                ) : QwtSymbol(style, brush, pen, size)
    {
        
    }

    ~QMySymbol()
    {
        qDebug() <<"this is my symbol";
    }
};

将最初的那句改成如下,参数使用派生类QMySymbol 指针。




编译,运行,都正常。然后程序退出的时候,成功的打印出了析构函数中的标记:


说明,最后内存还是在某个地方被释放掉了,由于不是在那个语句结束的语句块,而是在程序退出的时候,说明是在随着某个大对象一起析构的。

Qt的对象树机制(父对象与子对象,区别于标准C++继承关系中的父类与子类)帮助缓解了一部分的内存管理工作。可是今天这个例子,显然的并没有设置父指针(一般父指针的设置都是在构造函数中传入一个指针,而且QwtSymbol 这个类也没有setParent() 成员函数),所以这里的内存释放机制并不是透明的,暂且只能当作经验来记住了。

C++继承时,派生类对象的构造过程中会先构造基类的subobject,然后才是成员;实际上,QT中的子对象通常是成员指针所指向的堆上的一个对象(或者是派生类的构造函数中的一个局部指针),当然在析构是,这个成员指针的释放是自动的,但是,这个成员指针所指的堆上的对象,必须显示的在派生类的析构函数中delete 掉,QT的对象树的好处就在于,设置了父指针之后,再也可以不用去显示的释放掉这个对象,而会跟随着派生类对象的析构而析构。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值