Tutorial de RAII para C++
(4)
Me gustaría aprender a usar RAII en c ++. Creo que sé lo que es, pero no tengo idea de cómo implementarlo en mis programas. Una búsqueda rápida en Google no mostró ningún buen tutorial.
¿Alguien tiene buenos enlaces para enseñarme RAII?
El ítem 13 de "Effective C +" también es bastante útil
La explicación de wikipedia no está mal.
La referencia que personalmente he encontrado más útil sobre el tema de RAII es el libro Exceptional C ++ de Herb Sutter.
Muchos de los temas tratados en ese libro se mencionan en los artículos del gurú de la semana de Sutter. Esos artículos están disponibles en http://gotw.ca/gotw/index.htm .
No hay nada de eso (es decir, no creo que necesites un tutorial completo).
RAII se puede explicar brevemente como "Todo recurso que requiera limpieza debe asignarse al constructor de un objeto".
En otras palabras:
Los punteros deben estar encapsulados en clases de punteros inteligentes (vea std :: auto_ptr, boost :: shared_ptr y boost :: scoped_ptr para ver ejemplos).
Las manijas que requieren limpieza deben estar encapsuladas en clases que automáticamente liberan / liberan las manijas al destruirlas.
La sincronización debe basarse en la liberación de la primitiva exclusión mutua / sincronización al salir del alcance (para un ejemplo, consulte boost :: mutex :: scoped_lock usage).
No creo que realmente puedas tener un tutorial sobre RAII (como tampoco puedes tener uno sobre patrones de diseño). RAII es más una manera de ver los recursos que cualquier otra cosa.
Por ejemplo, en este momento estoy codificando usando WinAPI y escribí la siguiente clase:
template<typename H, BOOL _stdcall CloseFunction(H)>
class checked_handle
{
public:
typedef checked_handle<H,CloseFunction> MyType;
typedef typename H HandleType;
static const HandleType NoValue;
checked_handle(const HandleType value)
: _value(value)
{
}
~checked_handle()
{
Close();
}
HandleType* operator &()
{
return &_value;
}
operator HandleType()
{
return _value;
}
private:
HandleType _value;
void Close(const HandleType newValue = NoValue)
{
CloseFunction(_value);
_value = newValue;
}
};
template<typename H,BOOL _stdcall CloseFunction(H)>
const typename checked_handle<H,CloseFunction>::HandleType
checked_handle<H,CloseFunction>::NoValue =
checked_handle<H,CloseFunction>::HandleType(INVALID_HANDLE_VALUE);
typedef checked_handle<HANDLE,::CloseHandle> CheckedHandle;
typedef checked_handle<HWINSTA,::CloseWindowStation> WinStationHandle;
typedef checked_handle<HDESK,::CloseDesktop> DesktopHandle;
typedef checked_handle<HDEVNOTIFY,::UnregisterDeviceNotification> DevNotifyHandle;
typedef checked_handle<HWND,::DestroyWindow> WindowHandle;
BOOL __stdcall CloseKey(HKEY hKey);
typedef checked_handle<HKEY,CloseKey> RegHandle;
Esta clase no incluye la semántica de asignación y copia (las eliminé para proporcionar un ejemplo mínimo) por lo que devolver por valor hará que los identificadores se cierren dos veces.
Así es como se usa:
declaración de clase:
class Something
{
public:
// ...
private:
WindowHandle _window;
};
Este miembro está asignado pero nunca llamo a ::CloseWindow(_window._handle)
explícitamente (se llamará cuando las instancias de Something
salgan del alcance (como Something::~Something
-> WindowHandle::WindowHandle
-> ::Close(_window._value)
).