2010-04-14 11 views
29

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.Tutorial de RAII para C++

¿Alguien tiene algún enlace para enseñarme RAII?

+5

No es un enlace externo, pero puede encontrar algunas respuestas agradables aquí: http://stackoverflow.com/questions/395123/raii-and-smart-pointers-in-c – Naveen

+0

@Naveen - gracias, ese no aparece en mis enlaces cuando escribí mi título –

+1

@Joe Bloggs: uso google con el sitio: stackoverflow.com. Produce resultados mucho mejores. – Naveen

Respuesta

23

No hay nada de eso (es decir, no creo que necesite un tutorial completo).

RAII se puede explicar brevemente como "Todos los recursos que requieren limpieza deben asignarse al constructor de un objeto".

En otras palabras:

punteros debe ser encapsulado en las clases de puntero inteligente (ver std :: auto_ptr, impulsar :: shared_ptr e impulsar :: scoped_ptr para ejemplos).

Las manijas que requieren limpieza deben estar encapsuladas en clases que liberen/suelten automáticamente las manijas al destruirlas.

La sincronización debe basarse en la liberación de la primitiva de muteína/sincronización al salir del alcance (para obtener un ejemplo, consulte boost :: mutex :: scoped_lock usage).

No creo que realmente pueda tener un tutorial sobre RAII (no más de lo que puede tener uno en patrones de diseño, por ejemplo). RAII es más una manera de ver los recursos que cualquier otra cosa.

Por ejemplo, en el momento en que estoy de codificación usando WinAPI y yo escribió la clase siguiente:

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 asignación y copia semántica (I ellos elimina para proporcionar un ejemplo mínimo) por lo tanto, devolver por valor hará que los controladores se cierren dos veces.

Así es como se usa: declaración

clase:

class Something 
{ 
public: 
    // ... 
private: 
    WindowHandle  _window; 
}; 

Este miembro se asigna pero nunca llamar ::CloseWindow(_window._handle) explícitamente (que se llamará cuando las instancias de Something salir de su ámbito (como Something::~Something - >WindowHandle::WindowHandle -.>::Close(_window._value))

+3

Esto también se puede lograr usando 'boost :: shared_ptr' con un separador personalizado. Por ejemplo, 'boost :: shared_ptr checked_handle (open_some_handle(), boost :: bind < void > (& :: CloseHandle, _1));' –

+1

Buen punto, pero escribiría eso con algún tipo de definición al menos. No me gusta mucho usar una clase llamada "shared_ptr" para algo más que un puntero. Lleva a un desastre en el mantenimiento. – utnapistim

+0

En cierto sentido, un mango ES un puntero. Es una representación de algún recurso utilizando un tipo de datos primitivo (es decir, apunta a un recurso usando un número entero, generalmente). –

2

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 abordan en los artículos del gurú de la semana de Sutter. Esos artículos están disponibles en http://gotw.ca/gotw/index.htm.

+2

¿Qué capítulo de Exceptional C++ cubre el tema de RAII? – Javier