关于retainCount、指针的问题

moon_prince 发布于 2012/01/09 08:42
阅读 2K+
收藏 1
现创建一个Car类,它含有一个实例变量:
Engine *engine
有一个初始化的方法:
-(id)init{
 if(self=[super init])
{
 engine=[Engine new];
}
}
还有一个方法:
-(void)setEngine: (Engine *) newEngine
{
  [engine release];
 engine=[newEngine retain];
}

现有主函数如下:
{
 Engine *engine=[Engine new];
Car *car1=[Car new];
Car *car2=[Car new];

[car1 setEngine:engine];
[engine release];

[car2 setEngine:[car1 engine]];

现 在不明白的是书里面的一段话:“[car1 engine]返回一个指向engine对象的指针,该对象的保留计数器值为1。setEngine方法的第一行是[engine release],该语句将engine对象的保留计数器归为0,并释放engine对象。现在,newEngine和engine这两个实例变量都指向 刚释放的内存区,这会引起错误。”

疑问在:“newEngine和engine这两个实例变量都指向刚释放的内存区”。       按照我自己的理解,这里面所指的newEngine和engine都是car2类里面的实例变量,[car2 setEngine:[car1 engine]];这一句令两个变量都指向car1类里面的engine实例变量,而此时car1类里面的engine实例变量的retainCount 应该为1吧。(car1类里边的 engine初始化一次,release了一次, engine=[newEngine retain];---->engine的retainCount又成了1)          那么怎么说“这两个实例变量都指向刚释放的内存区”,好像是说指针都指向主函数里面另外一个刚release掉的engine。可是这样违背了原理吧?

看了有点乱,希望大家帮我解释清楚这句话。
加载中
0
TrulyBelieve
TrulyBelieve

[car1 engine],理论上是一个属性方法,即get请求,意思是获取一个对象给别人,所以在该方法内应该将计数器+1,这时计数器应该为2,而不是1,不能简单作为成员变量赋值给其他引用或对象。

你把[car2 setEngine:[car1 engine]];

改成

Engine *engine = [car1 engine];

[engine retain];

[car1 setEngine:engine];

还算讲得通

0
TrulyBelieve
TrulyBelieve
//书上讲的我认为是以下情景

Engine *engine=[Engine new]; // 计数器为1
Car *car1=[Car new]; 
Car *car2=[Car new]; 

[car1 setEngine:engine]; // 2,[nil release] 不起作用
[engine release];  // 1

// [car2 setEngine:[car1 engine]]拆成两步; 
[car1 engine] // 1,个人认为这个应该在程序上将计数器+1
[engine release] // 0
engine=[newEngine retain]; //出错


0
moon_prince
moon_prince
[car1 engine] // 1,个人认为这个应该在程序上将计数器+1  ??????
[car1 engine]只是将指针赋给car2方法的newEngine参数吧,并没有retain过,怎么会+1呢?

[engine release] // 0    ??????

engine被release后计数为0,engine=[newEngine retain];之后engine的计数不应该增加了吗?怎么会出错?

我的指针学得不太好,望不吝指教,呵呵:-)
0
moon_prince
moon_prince
哦,这样写我就很明白了,我再整体理解下。。。
0
moon_prince
moon_prince
你最后应该写错了吧,是 [car2 setEngine:engine];
TrulyBelieve
TrulyBelieve
恩,写错了
0
moon_prince
moon_prince

[car1 engine],理论上是一个属性方法,即get请求,意思是获取一个对象给别人,所以在该方法内应该将计数器+1,这时计数器应该为2

我们可不可以这样子理解,[car2 setEngine:engine]====>同义于[car1.engine retain] 后,car2里面的newEngine指向它?

0
moon_prince
moon_prince

Engine *engine = [car1 engine];

[engine retain];

这里面的

[engine retain];目的就是你说的:获取一个对象给别人。。是这个意思吧?

TrulyBelieve
TrulyBelieve
对。两个途径访问同一对象,相当于两个人可以开同一扇门,理应每人一把钥匙,计数器为2。
0
moon_prince
moon_prince

你讲得非常不错。。。不过不要怪我啰嗦,呵呵,还有一点问题:

// [car2 setEngine:[car1 engine]]拆成两步;
[car1 engine] // 1,个人认为这个应该在程序上将计数器+1
[engine release] // 0
engine=[newEngine retain]; //出错

----------------------------------------------------------------------

在[car2 setEngine:[car1 engine]]之前,car1里的engine变量最后为1,按照[car1 engine]等价[car1.engine retain]来说,car1.engine此时的计数器应该为2才对,怎么还是1呢?

还有一点不懂的就是:[engine release] // 0
engine=[newEngine retain]; //出错

release的是car2自己的实例变量engine,newEngine指向car1.Engine(就按照你说的计数器为1),那么怎么会出错呢?car1.Engine没被release吧?有的话在哪被release了?

0
TrulyBelieve
TrulyBelieve
STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
STDMETHOD_(ULONG, Release)()
{
ULONG l = InternalRelease();
if (l == 0)
delete this;
return l;
}
// 摘自微软VC中COM的一点源代码,InternalAddRef和InternalRelease可以看成计数器加一、减一,计数器当为0时会释放内部变量甚至自己。
0
TrulyBelieve
TrulyBelieve

计数器不为0,说明还有钥匙在别人手中,他随时都要使用

计数器为0,说明没有钥匙了,那这门还有谁能打开呢?^_^

返回顶部
顶部