Is there a reason why CFRelease does not check for NULL? Isn't it unacceptable when [nil release]; free(NULL); delete NULL; all work perfectly fine?
All of these functions are part of different APIs that follow different conventions with regards to handling NULL
:
CFRelease
is part of the CoreFoundation C SDK, which does not acceptNULL
reference as arguments by default.[nil release]
uses Objective-C (which allows dereferences ofnil
)free(NULL)
is part of C library (libc
) which permitsNULL
argumentsdelete NULL
is part of the C++ library (libc++
) which permitsNULL
arguments
I guess the CoreFoundation
SDK writers decided to be more consistent with the rest of SDK rather than with similar function in other SDKs.
Good point, it doesn't seem to make much sense at first glance. Of course, the behavior is properly documented, but it would be nice if it could handle NULL
gracefully. Notice that CFRetain
and CFMakeCollectable
(new in 10.4, GC enabled in 10.5) exhibit the same behavior. I'm not privy to all the motivations for designing it that way, but the emphasis was probably more on internal consistency with the rest of the CoreFoundation framework.
It's difficult/impossibly to know why CF was designed that way unless you can ask one of the designers. My best guess is that the designers decided that passing NULL for memory management functions is (should be?) a programming error. One could argue that causing a crash on NULL is a desirable "fail-fast" behavior, since bugs that crash almost immediately are easier to track down than bugs which silently do nothing instead of what you expect. Personally, I prefer the do-nothing-on-null approach, but I guess that's life...
Given that the API can't/won't change, you can either test for NULL or work around the problem case. One option might be to define an inline function or macro that only calls CFRelease for non-NULL references. In any case, it's probably best to be explicit in your code to avoid confusion down the road.
The source code to CoreFoundation is publicly available. Specifically, for Snow Leopard the code to CFRelease is in http://www.opensource.apple.com/source/CF/CF-550/CFRuntime.c
Here is what the relevant portion looks like:
void CFRelease(CFTypeRef cf) {
if (NULL == cf) HALT;
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
if (CF_IS_COLLECTABLE(cf)) {
if (CFTYPE_IS_OBJC(cf)) {
// release the GC-visible reference.
auto_zone_release(auto_zone(), (void*)cf);
} else {
// special-case CF objects for better performance.
_CFRelease(cf);
}
return;
}
#endif
}
This doesn't answer your question about design motivations, but you also asked why CFRelease does not check for NULL. It does check, and fails on purpose when NULL is passed as the parameter.
My personal belief is similar to Quinn's- that the CF designers felt it is a programming error to pass NULL.