Hay excelentes respuestas por ahí, así que solo agrego algunas cosas olvidadas.
0. RAII se trata de alcances
RAII se trata de ambos:
- adquirir un recurso (no importa qué recurso) en el constructor y deshacerlo en el destructor.
- tener el constructor ejecutado cuando se declara la variable, y el destructor ejecutado automáticamente cuando la variable sale del alcance.
Otros ya respondieron sobre eso, así que no daré más detalles.
1. Al codificar en Java o C #, ya usa RAII ...
JOURDAIN: ¡Qué! Cuando digo: "Nicole, tráeme mis pantuflas y dame mi gorro de dormir", ¿eso es prosa?
MAESTRO DE FILOSOFÍA: Sí, señor.
JOURDAIN: Hace más de cuarenta años que hablo en prosa sin saber nada al respecto, y le estoy muy agradecido por haberme enseñado eso.
- Molière: El caballero de la clase media, acto 2, escena 4
Como hizo Monsieur Jourdain con la prosa, C # e incluso la gente de Java ya usa RAII, pero de manera oculta. Por ejemplo, el siguiente código Java (que se escribe de la misma manera en C # reemplazando synchronized
con lock
):
void foo()
{
// etc.
synchronized(someObject)
{
// if something throws here, the lock on someObject will
// be unlocked
}
// etc.
}
... ya está usando RAII: La adquisición de mutex se realiza en la palabra clave ( synchronized
o lock
), y la des-adquisición se realizará al salir del alcance.
Es tan natural en su notación que casi no requiere explicación incluso para las personas que nunca han oído hablar de RAII.
La ventaja que tiene C ++ sobre Java y C # aquí es que se puede hacer cualquier cosa con RAII. Por ejemplo, no hay un equivalente integrado directo de synchronized
ni lock
en C ++, pero aún podemos tenerlos.
En C ++, estaría escrito:
void foo()
{
// etc.
{
Lock lock(someObject) ; // lock is an object of type Lock whose
// constructor acquires a mutex on
// someObject and whose destructor will
// un-acquire it
// if something throws here, the lock on someObject will
// be unlocked
}
// etc.
}
que se puede escribir fácilmente de forma Java / C # (usando macros C ++):
void foo()
{
// etc.
LOCK(someObject)
{
// if something throws here, the lock on someObject will
// be unlocked
}
// etc.
}
2. RAII tiene usos alternativos
CONEJO BLANCO: [cantando] Llego tarde / Llego tarde / Para una cita muy importante. / No hay tiempo para decir "Hola". / Adiós. / Llego tarde, llego tarde, llego tarde.
- Alicia en el país de las maravillas (versión Disney, 1951)
Sabe cuándo se llamará al constructor (en la declaración del objeto), y sabe cuándo se llamará a su destructor correspondiente (a la salida del alcance), por lo que puede escribir código casi mágico con solo una línea. Bienvenido al país de las maravillas de C ++ (al menos, desde el punto de vista de un desarrollador de C ++).
Por ejemplo, puede escribir un objeto contador (lo dejé como un ejercicio) y usarlo simplemente declarando su variable, como se usó el objeto de bloqueo anterior:
void foo()
{
double timeElapsed = 0 ;
{
Counter counter(timeElapsed) ;
// do something lengthy
}
// now, the timeElapsed variable contain the time elapsed
// from the Counter's declaration till the scope exit
}
que, por supuesto, se puede escribir, nuevamente, de la forma Java / C # usando una macro:
void foo()
{
double timeElapsed = 0 ;
COUNTER(timeElapsed)
{
// do something lengthy
}
// now, the timeElapsed variable contain the time elapsed
// from the Counter's declaration till the scope exit
}
3. ¿Por qué falta C ++ finally
?
[GRITOS] ¡Es la cuenta regresiva final !
- Europa: The Final Countdown (lo siento, me quedé sin comillas, aquí ... :-)
La finally
cláusula se usa en C # / Java para manejar la eliminación de recursos en caso de salida del alcance (ya sea a través de una return
excepción lanzada).
Los lectores de especificaciones astutos habrán notado que C ++ no tiene una cláusula final. Y esto no es un error, porque C ++ no lo necesita, ya que RAII ya maneja la eliminación de recursos. (Y créame, escribir un destructor C ++ es mucho más fácil que escribir la cláusula final correcta de Java, o incluso el método Dispose correcto de C #).
Aún así, a veces, una finally
cláusula sería genial. ¿Podemos hacerlo en C ++? ¡Si podemos! Y nuevamente con un uso alternativo de RAII.
Conclusión: RAII es más que una filosofía en C ++: es C ++
RAII? ESTO ES C ++ !!!
- Comentario indignado del desarrollador de C ++, copiado descaradamente por un oscuro rey de Esparta y sus 300 amigos
Cuando alcanzas algún nivel de experiencia en C ++, empiezas a pensar en términos de RAII , en términos de ejecución automatizada de constructores y destructores .
Empieza a pensar en términos de alcances y los caracteres {
y se }
convierten en los más importantes de su código.
Y casi todo encaja perfectamente en términos de RAII: seguridad de excepción, mutex, conexiones de base de datos, solicitudes de base de datos, conexión de servidor, relojes, identificadores de SO, etc., y por último, pero no menos importante, memoria.
La parte de la base de datos no es despreciable, ya que, si aceptas pagar el precio, incluso puedes escribir en un estilo de " programación transaccional ", ejecutando líneas y líneas de código hasta decidir, al final, si quieres realizar todos los cambios. o, si no es posible, revertir todos los cambios (siempre que cada línea satisfaga al menos la Garantía de excepción sólida). (vea la segunda parte de este artículo de Herb's Sutter para la programación transaccional).
Y como un rompecabezas, todo encaja.
RAII es una parte tan importante de C ++ que C ++ no podría ser C ++ sin él.
Esto explica por qué los desarrolladores de C ++ experimentados están tan enamorados de RAII y por qué RAII es lo primero que buscan cuando prueban otro idioma.
Y explica por qué Garbage Collector, aunque es una magnífica pieza de tecnología en sí misma, no es tan impresionante desde el punto de vista de un desarrollador de C ++:
- RAII ya maneja la mayoría de los casos manejados por un GC
- Un GC maneja mejor que RAII con referencias circulares en objetos administrados puros (mitigados por usos inteligentes de punteros débiles)
- Aún así, un GC está limitado a la memoria, mientras que RAII puede manejar cualquier tipo de recurso.
- Como se describió anteriormente, RAII puede hacer mucho, mucho más ...