objective-c core-foundation

objective c - ¿Por qué CFRelease(NULL) se bloquea?



objective-c core-foundation (4)

¿Hay alguna razón por la que CFRelease no verifique si está NULL? ¿No es inaceptable cuando [lanzamiento nulo]; libre (NULL); eliminar NULL; todo funciona perfectamente bien?


Buen punto, no parece tener mucho sentido a primera vista. Por supuesto, el comportamiento está bien documentado , pero sería bueno si pudiera manejar NULL gracia. Observe que CFRetain y CFMakeCollectable (nuevo en 10.4, GC habilitado en 10.5) muestran el mismo comportamiento. No estoy al tanto de todas las motivaciones para diseñarlo de esa manera, pero el énfasis fue probablemente más en la consistencia interna con el resto del marco CoreFoundation.

Es difícil / imposible saber por qué CF se diseñó de esa manera, a menos que pueda preguntarle a uno de los diseñadores. Mi mejor conjetura es que los diseñadores decidieron que pasar NULL para las funciones de administración de memoria es (debería ser?) Un error de programación. Se podría argumentar que causar un bloqueo en NULL es un comportamiento deseable de "falla rápida", ya que los errores que se bloquean casi de inmediato son más fáciles de localizar que los errores que no hacen nada en lugar de lo que usted espera. Personalmente, prefiero el enfoque de no hacer nada en nulo, pero supongo que es la vida ...

Dado que la API no puede / no cambiará, puede probar NULL o solucionar el caso del problema. Una opción podría ser definir una función o macro en línea que solo llame a CFRelease para referencias que no sean NULL. En cualquier caso, probablemente es mejor ser explícito en su código para evitar confusiones en el camino.


El código fuente de CoreFoundation está disponible públicamente. Específicamente, para Snow Leopard el código para CFRelease está en http://www.opensource.apple.com/source/CF/CF-550/CFRuntime.c

Aquí es cómo se ve la parte relevante:

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 }

Esto no responde a su pregunta sobre las motivaciones de diseño, pero también preguntó por qué CFRelease no verifica el valor NULL. Verifica, y falla a propósito cuando se pasa NULL como parámetro.

Mi creencia personal es similar a la de Quinn: que los diseñadores de CF consideraron que es un error de programación pasar NULL.


Puede consultar el código fuente de CFReleaseProtector para controlar (o comprender mejor) este problema.

CF No deje de bloquearse en NULL,

http://unsanity.org/archives/haxies/cfrelease_no_mo.php

Puede desempaquetar CFReleaseProtector.sit con la herramienta de línea de comandos unar (parte de The Unarchiver; consulte la lista de descargas de códigos de Google).


Todas estas funciones son parte de diferentes API que siguen diferentes convenciones con respecto al manejo de NULL :

  1. CFRelease es parte del SDK de CoreFoundation C, que no acepta la referencia NULL como argumentos de forma predeterminada.
  2. [nil release] usa Objective-C (que permite la eliminación de referencias de nil )
  3. free(NULL) es parte de la biblioteca C ( libc ) que permite argumentos NULL
  4. delete NULL es parte de la biblioteca de C ++ ( libc++ ) que permite argumentos NULL

Supongo que los escritores de CoreFoundation SDK decidieron ser más coherentes con el resto de SDK en lugar de con una función similar en otros SDK.