Unclear on -initWithBytesNoCopy:
Unclear on -initWithBytesNoCopy:
- Subject: Unclear on -initWithBytesNoCopy:
- From: Jens Alfke <email@hidden>
- Date: Sat, 03 Mar 2012 11:15:08 -0800
The documentation of -[NSData initWithBytesNoCopy:length:freeWhenDone:] and of -[NSString initWithBytesNoCopy:length:encoding:freeWhenDone:] is unclear about the case where freeWhenDone is NO. The data/string object then does not take ownership of the memory buffer, so the question is: How long is the caller obligated to keep the buffer intact?
The two possible answers seem to be
(a) until the caller releases the NSString object, or
(b) forever, until the process exits (i.e. only ever use this on constant buffers)
I’ve been using assumption (a). Obviously I avoid storing references to the string elsewhere. But as I said, the docs don’t say one way or the other, and I just got burned when porting some code to GNUstep (an open-source re-implementation of Cocoa), because they interpreted it according to (b). Here’s a simple test case:
char buffer[] = "I HAZ A BUFFER";
NSString* str = [[NSString alloc] initWithBytesNoCopy: buffer length: strlen(buffer) encoding: NSUTF8StringEncoding freeWhenDone: NO];
So far so good. We have an NSString that points into an ephemeral buffer I’ve provided.
NSString* substr = [str substringWithRange: NSMakeRange(2, 3)];
NSLog(@"substr = '%@'", substr);
Clearly substr is equal to @“HAZ”.
[str release];
memset(buffer, '*', sizeof(buffer));
I’m now done with str, so I release it, and having released it, it’s now safe to destroy the buffer it was using. Right?
NSLog(@"substr = '%@'", substr);
Here’s the conundrum. On OS X and iOS, substr is still equal to @“HAZ”, as I expected. On GNUstep it’s equal to @“***”! Why? Because GNUstep implements -substringWithRange: by creating a string that points directly into the parent string’s character buffer. Yes, it only does this if the parent string is immutable, and the substring retains the parent string. But this means that, from my perspective, my temporary buffer is now unexpectedly being used by a different object whose lifespan is greater than it.
I filed a bug report* saying that this substring optimization shouldn’t be used if the source string uses an external buffer, just as it shouldn’t if the source string is mutable. They fixed it, but some people there argue that their original implementation was correct (even if not compatible with Apple’s.) I’m curious, so I’m asking here to see if anyone knows for sure what’s intended.
—Jens
* https://savannah.gnu.org/bugs/index.php?35699
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden