views:

52

answers:

4

For example say I have:

NSMutableArray *array = [[NSMutableArray alloc] init];
NSMutableArray *array2 = array;
[array release];

is this legal? Do I just leave array2 dangling since I already released the object that was taking memory?

+2  A: 

As you suspect, array2 no longer refers to a valid object after you call [array release].

However, it's not clear what the value having of the second variable is. It would not be available to you anywhere that array isn't already available (they have the same scope), and since they both refer to the same object, you might as well just use one variable.

If you need a second array, or another reference that is valid after [array release], you could create a copy, or use NSMutableArray *array2 = [array retain]. Either way, you would need to release array2 at some point to avoid a memory leak.

Robot K
NSMutableArray *array = [[NSMutableArray alloc] init];NSMutableArray *array2 = [array retain];[array release];[array2 release]; .... this look right?
Shnitzel
It looks right to me, but it's hard for me to read code without line breaks.
Robot K
@Schnitzel: yes, it's right. @Robot K: retaining an array doesn't make a copy.
JeremyP
Yes, `array2` no longer refers to a valid object, *but neither does `array`*, so what's the difference?
invariant
@Jeremy - I didn't mean to imply that retain made a copy. I said you could copy it *or* retain it.
Robot K
@Robot K: sorry, I misread your answer.
JeremyP
+1  A: 

Variables array and array2 are merely C pointers to a chunk of memory. As with any heap-allocated chunk of memory in C, it has to be malloced() and freed(), which effectively determine the lifetime of the memory chunk in the absence of garbage collector. Obj-C objects are a little specialized chunks of memory, but the underlying mechanics is the same: a variant of calloc() and free().

So yes, after you send [array release] the array object's retain count reaches zero and the object immediately sends -dealloc to self, which calls free(). After that any attempt to access the chunk of memory occupied by the object will cause a crash (or worse yet, if another Obj-C object gets allocated at the same address, you will get crashes in unrelated places all over your code).

Since array2 is just another pointer to the same, now freed, chunk of memory, you can't do anything with it either. The best you can do is set such pointers to nil to prevent yourself from accidentally accessing memory you no longer own. Obj-C is smart enough to make messages sent to nil (messages sent to nil pointers) no-ops.

Costique
yes, i was thinking about setting array2 to nil, as I don't use array2 after array is released. However I kind of like Robot K's idea of increasing the retain count... and then releasing both. Working with the retain counts is a little prettier.. no?
Shnitzel
If you set `array2` to nil you should set `array` to nil too. It makes no sense to nil out one and not the other.
invariant
+1  A: 

You don't have do do anything!

The 'other' pointers are no different to the original pointer. They all point to the same thing. They are exactly equivalent to each other.

The thing to understand is that release has no effect on the pointer itself. I get the impression you think [array release] somehow does something to the array pointer leaving it somehow altered. It doesn't. Consider this code:

NSMutableArray *array = [[NSMutableArray alloc] init];
NSMutableArray *array2 = array;
[array2 release];

This is exactly equivalent to your code and just as legal. You can call release on either array or array2 and it has the exact same effect. Neither array or array2 is changed by the call. Only the object pointed to.

So there is no point retaining twice only to release twice. At the end of it, you are left with exactly the same situation: two pointers to a freed object.

You can nil them out if you want, but it's not necessary.

invariant
+1. I was trying to make this point as well, but you've stated much more clearly.
Robot K
Yes, you're right... but I just feel uneasy about it;), I think it's 'safer' in the long run to use a retain count.
Shnitzel
+1  A: 

Is this not just a question of code cleanliness?

If you want array2 to point to array, and you're going to be doing some work with array2, then I'd explicitly retain it:

NSMutableArray *array = [[NSMutableArray alloc] init];
NSMutableArray *array2 = [array retain];
[array release];
[array2 release];

This way, if someone else decides to do some work with array2 after [array release] is called, they won't run into memory problems.

Your original code is valid, but contains a nasty surprise for anyone using array2 after release is called.

Mr. Matt
This was Robot K's original suggestion but I'll mark you as the answer since you wrote out the code. This is what I decided to go with and seems like the most proper way to go about it.
Shnitzel