Re: Unclear on -initWithBytesNoCopy:
Re: Unclear on -initWithBytesNoCopy:
- Subject: Re: Unclear on -initWithBytesNoCopy:
- From: Dave Keck <email@hidden>
- Date: Sat, 03 Mar 2012 14:55:43 -0500
Hit send too soon...
> 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:
I hadn't thought about this problem before, but it suggests to me that
one should avoid using freeWhenDone == NO. Since supplying a
string/data object to any method or function could potentially retain
(or retain+autorelease) it, it would be exceedingly easy to create a
string/data object that has an invalid underlying buffer, thus calling
any method on this string/data object would result in a crash.
I suppose this scenario reinforces that if your method is passed a
NSString/NSData object and you need to keep it around longer than the
current stack frame, then you must copy the string/data object. I
suspect many methods don't do this though (including my own, I prefer
the caller to ensure that the string remains intact), which is why I
would avoid using freeWhenDone == NO unless a buffer is guaranteed to
last the entire process.
> 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.
>
I agree with your suggested implementation, because if I were to write
a method that calls -substringWithRange: on a string parameter passed
to me, I would never expect that substring to become invalid until my
method or its counterparts explicitly release it. That an outsider can
affect the contents of a string created with -substringWithRange:
seems like a bug to me.
_______________________________________________
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