【发布时间】:2009-07-16 03:06:32
【问题描述】:
CFRelease 不检查 NULL 是否有原因? [nil release] 时是不是不能接受;免费(空);删除空;一切正常吗?
【问题讨论】:
标签: objective-c core-foundation
CFRelease 不检查 NULL 是否有原因? [nil release] 时是不是不能接受;免费(空);删除空;一切正常吗?
【问题讨论】:
标签: objective-c core-foundation
CoreFoundation 的源代码是公开的。具体来说,对于 Snow Leopard,CFRelease 的代码位于 http://www.opensource.apple.com/source/CF/CF-550/CFRuntime.c
下面是相关部分的样子:
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
}
这并没有回答您关于设计动机的问题,但您还问了为什么 CFRelease 不检查 NULL。它确实会检查,并在将 NULL 作为参数传递时故意失败。
我个人的看法与 Quinn 的相似——CF 设计者认为传递 NULL 是一个编程错误。
【讨论】:
好点子,乍一看似乎没有多大意义。当然,behavior is properly documented,但如果它能够优雅地处理NULL,那就太好了。请注意,CFRetain 和 CFMakeCollectable(10.4 中新增,10.5 中启用了 GC)表现出相同的行为。我并不了解以这种方式设计它的所有动机,但重点可能更多地在于与 CoreFoundation 框架的其余部分的内部一致性。
很难/不可能知道为什么 CF 是这样设计的,除非您可以询问其中一位设计师。我最好的猜测是,设计者认为为内存管理函数传递 NULL 是(应该是?)一个编程错误。有人可能会争辩说,在 NULL 上导致崩溃是一种理想的“快速失败”行为,因为几乎立即崩溃的 bug 比默默不做任何事情而不是你所期望的 bug 更容易追踪。就个人而言,我更喜欢什么都不做的方法,但我想这就是生活......
鉴于 API 不能/不会更改,您可以测试 NULL 或解决问题案例。一种选择可能是定义一个只为非 NULL 引用调用 CFRelease 的内联函数或宏。无论如何,最好在您的代码中明确说明,以避免以后出现混淆。
【讨论】:
所有这些函数都是不同 API 的一部分,它们在处理 NULL 方面遵循不同的约定:
CFRelease 是 CoreFoundation C SDK 的一部分,默认情况下不接受 NULL 引用作为参数。[nil release] 使用 Objective-C(允许取消引用 nil)free(NULL) 是 C 库 (libc) 的一部分,它允许 NULL 参数delete NULL 是 C++ 库 (libc++) 的一部分,它允许 NULL 参数我猜CoreFoundation SDK 编写者决定与 SDK 的其余部分保持一致,而不是与其他 SDK 中的类似功能保持一致。
【讨论】:
您可以查看 CFReleaseProtector 的源代码来处理(或更好地理解)这个问题。
CFRelease NULL 不再崩溃,
http://unsanity.org/archives/haxies/cfrelease_no_mo.php
您可以使用命令行工具 unar(The Unarchiver 的一部分;参见其 Google 代码下载列表)解压缩 CFReleaseProtector.sit。
【讨论】: