简体   繁体   中英

why not EXC_BAD_ACCESS?

I've written the following code:

NSString *string = [[NSString alloc] initWithFormat:@"test"];
[string release];

NSLog(@"string lenght = %d", [string length]);
//Why I don't get EXC_BAD_ACCESS at this point?

I should, it should be released. The retainCount should be 0 after last release, so why is it not?

PS I am using latest XCode.

Update:

NSString *string = [[NSString alloc] initWithFormat:@"test"];

NSLog(@"retainCount before = %d", [string retainCount]);// => 1

[string release];

NSLog(@"retainCount after = %d", [string retainCount]);// => 1 Why!?

In this case, the frameworks are likely returning the literal @"test" from NSString *string = [[NSString alloc] initWithFormat:@"test"]; . That is, it determines the literal may be reused, and reuses it in this context. After all, the input matches the output.

However, you should not rely on these internal optimizations in your programs -- just stick with the reference counting rules and well-defined behavior.

Update

David's comment caused me to look into this. On the system I tested, NSString *string = [[NSString alloc] initWithFormat:@"test"]; returns a new object. Your program messages an object which should have been released, and is not eligible for the immortal string status.

Your program still falls into undefined territory, and happens to appear to give the correct results in some cases only as an artifact of implementation details -- or just purely coincidence. As David pointed out, adding 'stuff' between the release and the log can cause string to really be destroyed and potentially reused. If you really want to know why this all works, you could read the objc runtime sources or crawl through the runtime's assembly as it executes. Some of it may have an explanation (runtime implementation details), and some of it is purely coincidence.

Doing things to a released object is an undefined behavior. Meaning - sometimes you get away with it, sometimes it crashes, sometimes it crashes a minute later in a completely different spot, sometimes a variable ten files away gets mysteriously modified.

To catch those issues, use the NSZombie technique. Look it up. That, and some coding discipline.

This time, you got away because the freed up memory hasn't been overwritten by anything yet. The memory that string points at still contains the bytes of a string object with the right length. Some time later, something else will be there, or the memory address won't be valid anymore. And there's no telling when this happens.

Sending messages to nil objects is, however, legitimate. That's a defined behavior in Objective C, in fact - nothing happens, 0 or nil is returned.

Update:

Ok. I'm tired and didn't read your question carefully enough.

The reason you are not crashing is pure luck . At first I though that you were using initWithString: in which case all the answers (including my original one (below)) about string literals would be valid.


What I mean by "pure luck"

The reason this works is just that the object is released but your pointer still points to where it used to be and the memory is not overwritten before you read it again. So when you access the variable you read from the untouched memory which means that you get a valid object back. Doing the above is VERY dangerous and will eventually cause a crash in the future!

If you start creating more object in between the release and the log then there is a chance that one of them will use the same memory as your string had and then you would crash when trying to read the old memory.

It is even so fragile that calling log twice in a row will cause a crash.


Original answer:

String literals never get released!

Take a look at my answer for this question for a description of why this is.

This answer also has a good explanation.

One possible explanation: You're superfluously dynamically allocating a string instead of just using the constant. Probably Cocoa already knows that's just a waste of memory (if you're not creating a mutable string), so it maybe releases the allocated object and returns the constant string instead. And on a constant string, release and retain have no effect.

To prove this, it's worth comparing the returned pointer to the constant string itself:

int main()
{
    NSString *s = @"Hello World!";
    NSString *t = [[NSString alloc] initWithFormat:s];

    if (s == t)
        NSLog(@"Strings are the same");
    else
        NSLog(@"Not the same; another instance was allocated");

    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM