Chinaunix首页 | 论坛 | 博客
  • 博客访问: 384806
  • 博文数量: 158
  • 博客积分: 1227
  • 博客等级: 少尉
  • 技术积分: 946
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-20 16:19
文章分类
文章存档

2016年(1)

2015年(1)

2012年(107)

2011年(49)

分类: 嵌入式

2012-03-27 16:52:50

原文地址:

在QT的程序中经常会看到只有new而不delete的情况,其实是因为QT有一套回收内存的机制,主要的规则如下:
1.所有继承自QOBJECT类的类,如果在new的时候指定了父亲,那么它的清理时在父亲被delete的时候delete的,所以如果一个程序中,所有的QOBJECT类都指定了父亲,那么他们是会一级级的在最上面的父亲清理时被清理,而不用自己清理;
2.程序通常最上层会有一个根的QOBJECT,就是放在setCentralWidget()中的那个QOBJECT,这个QOBJECT在 new的时候不必指定它的父亲,因为这个语句将设定它的父亲为总的QAPPLICATION,当整个QAPPLICATION没有时它就自动清理,所以也 无需清理。9这里QT4和QT3有不同,QT3中用的是setmainwidget函数,但是这个函数不作为里面QOBJECT的父亲,所以QT3中这个 顶层的QOBJECT要自行销毁)。
3.这是有人可能会问那如果我自行delete掉这些QT接管负责销毁的指针了会出现什么情况呢,如果时这样的话,正常情况下QT的拥有这个对 象的 那个父亲会知道这件事情,它会直到它的儿子被你直接DELETE了,这样它会将这个儿子移出它的列表,并且重新构建显示内容,但是直接这样做时有风险的! 也就是要说的下一条
4.当一个QOBJECT正在接受事件队列时如果中途被你DELETE掉了,就是出现问题了,所以QT中建议大家不要直接DELETE掉一个 QOBJECT,如果一定要这样做,要使用QOBJECT的deleteLater()函数,它会让所有事件都发送完一切处理好后马上清除这片内存,而且 就算调用多次的deletelater也不会有问题。
5.QT不建议在一个QOBJECT 的父亲的范围之外持有对这个QOBJECT的指针,因为如果这样外面的指针很可能不会察觉这个QOBJECT被释放,会出现错误,如果一定要这样,就要记 住你在哪这样做了,然后抓住那个被你违规使用的QOBJECT的destroyed()信号,当它没有时赶快置零你的外部指针。当然我认为这样做是及其麻 烦也不符合高效率编程规范的,所以如果要这样在外部持有QOBJECT的指针,建议使用引用或者用智能指针,如QT就提供了智能指针针对这些情况,见最后 一条。
6.QT中的智能指针封装为QPointer类,所有QOBJECT的子类都可以用这个智能指针来包装,很多用法与普通指针一样,可以详见QT assistant
通过调查这个QT的内存管理功能,发现了很多东西,现在觉得虽然这个QT弄的有点小复杂,但是使用起来还是很方便的,最后要说的是某些内存泄露的检测工具会认为QT的程序因为这种方式存在内存泄露,发现时大可不必理会~ ~

原文地址:

new 和 delete

Objective-C 中没有 new 和 delete 这两个关键字(new 可以看作是一个函数,也就是 alloc+init)。它们实际是被 alloc 和 release 所取代。

引用计数

内存管理是一个语言很重要的部分。在 C 和 C++ 中,内存块有一次分配,并且要有一次释放。这块内存区可以被任意多个指针指向,但只能被其中一个指针释放。Objective-C 则使用引用计数。对象知道自己被引用了多少次,这就像狗和狗链的关系。如果对象是一条狗,每个人都可以拿狗链拴住它。如果有人不想再管它了,只要丢掉他手 中的狗链就可以了。只要还有一条狗链,狗就必须在那里;但是只要所有的狗链都没有了,那么此时狗就自由了。换做技术上的术语,新创建的对象的引用计数器被 设置为 1。如果代码需要引用这个对象,就可以发送一个 retain 消息,让计数器加 1。当代码不需要的时候则发送一个 release 消息,让计数器减 1。

对象可以接收任意多的 retain 和 release 消息,只要计数器的值是正的。当计数器成 0 时,析构函数 dealloc 将被自动调用。此时再次发送 release 给这个对象就是非法的了,将引发一个内存错误。

这种技术并不同于 C++ STL 的 auto_ptr。Boost 库提供了一个类似的引用计数器,称为 shared_ptr,但这并不是标准库的一部分。

alloc, copy, mutableCopy, retain, release

明白了内存管理机制并不能很好的使用它。这一节的目的就是给出一些使用规则。这里先不解释 autorelease 关键字,因为它比较难理解。

基本规则是,所有使用 alloc,[mutable]copy[WithZone:] 或者是 retain 增加计数器的对象都要用 [auto]release 释放。事实上,有三种方法可以增加引用计数器,也就意味着仅仅有有限种情况下才要使用 release 释放对象:

使用 alloc 显式实例化对象;
使用 copy[WithZone:] 或者 mutableCopy[WithZone:] 复制对象(不管这种克隆是不是伪克隆);
使用 retain。
记住,默认情况下,给 nil 发送消息(例如 release)是合法的,不会引起任何后果。

autorelease

不一样的 autorelease

前面我们强调了,所有使用 alloc,[mutable]copy[WithZone:] 或者是 retain 增加计数器的对象都要用 [auto]release 释放。事实上,这条规则不仅仅适用于 alloc、retain 和 release。有些函数虽然不是构造函数,但也用于创建对象,例如 C++ 的二元加运算符(obj3 operator+(obj1, obj2))。在 C++ 中,返回值可以在栈上,以便在离开作用域的时候可以自动销毁。但在 Objective-C 中不存在这种对象。函数使用 alloc 分配的对象,直到将其返回栈之前不能释放。下面的代码将解释这种情况:

01// 第一个例子
02-(Point2D*) add:(Point2D*)p1 and:(Point2D*)p2
03{
04    Point2D* result = [[Point2D alloc] initWithX:([p1 getX] + [p2 getX])
05                                            andY:([p1 getY] + [p2 getY])];
06    return result;
07}
08 
09// 错误!这个函数使用了 alloc,所以它将对象的引用计数器加 1。
10// 根据前面的说法,它应该被销毁。
11// 但是这将引起内存泄露:
12[calculator add:[calculator add:p1 and:p2] and:p3];
13// 第一个算式是匿名的,没有办法 release。所以引起内存泄露。
14 
15// 第二个例子
16-(Point2D*) add:(Point2D*)p1 and:(Point2D*)p2
17{
18    return [[Point2D alloc] initWithX:([p1 getX] + [p2 getX])
19                                 andY:([p1 getY] + [p2 getY])];
20}
21// 错误!这段代码实际上和上面的一样,
22// 不同之处在于仅仅减少了一个中间变量。
23 
24// 第三个例子
25-(Point2D*) add:(Point2D*)p1 and:(Point2D*)p2
26{
27    Point2D* result = [[Point2D alloc] initWithX:([p1 getX] + [p2 getX])
28                                            andY:([p1 getY] + [p2 getY])];
29    [result release];
30    return result;
31}
32// 错误!显然,这里仅仅是在对象创建出来之后立即销毁了。

这个问题看起来很棘手。如果没有 autorelease 的确如此。简单地说,给一个对象发送 autorelease 消息意味着告诉它,在“一段时间之后”销毁。但是这里的“一段时间之后”并不意味着“任何时间”。我们将在后面的章节中详细讲述这个问题。现在,我们有了 上面这个问题的一种解决方案:

1-(Point2D*) add:(Point2D*)p1 and:(Point2D*)p2
2{
3    Point2D* result = [[Point2D alloc] initWithX:([p1 getX] + [p2 getX])
4                                            andY:([p1 getY] + [p2 getY])];
5    [result autorelease];
6    return result; // 更简短的代码是:return [result autorelease];
7}
8// 正确!result 将在以后自动释放
阅读(2271) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~