2010-04-14 56 views
29

Tôi muốn tìm hiểu cách sử dụng RAII trong C++. Tôi nghĩ rằng tôi biết nó là gì, nhưng không có ý tưởng làm thế nào để thực hiện nó trong các chương trình của tôi. Tìm kiếm nhanh trên google không hiển thị bất kỳ hướng dẫn hay nào.Hướng dẫn RAII cho C++

Có ai có liên kết tốt đẹp nào để dạy tôi RAII không?

+5

Không phải là một liên kết bên ngoài, nhưng bạn có thể tìm thấy một số câu trả lời hay ở đây: http://stackoverflow.com/questions/395123/raii-and-smart-pointers-in-c – Naveen

+0

@Naveen - cảm ơn, điều đó không hiển thị trong các liên kết của tôi khi tôi nhập vào tiêu đề –

+1

@Joe Bloggs: Tôi sử dụng google với trang web: stackoverflow.com. Nó tạo ra kết quả tốt hơn nhiều. – Naveen

Trả lời

23

Không có gì với nó (nghĩa là, tôi không nghĩ bạn cần một hướng dẫn đầy đủ).

RAII có thể được giải thích ngắn gọn là "Mọi tài nguyên yêu cầu dọn dẹp nên được trao cho hàm tạo của đối tượng."

Nói cách khác:

Pointers nên được đóng gói trong các lớp con trỏ thông minh (xem std :: auto_ptr, đẩy mạnh :: shared_ptr và đẩy mạnh :: scoped_ptr cho ví dụ).

Xử lý yêu cầu dọn dẹp nên được đóng gói trong các lớp tự động giải phóng/giải phóng các tay cầm sau khi tiêu hủy.

Đồng bộ hóa nên dựa vào việc phát hành nguyên gốc mutex/đồng bộ hóa khi thoát khỏi phạm vi (xem boost :: mutex :: scoped_lock usage cho ví dụ).

Tôi không nghĩ rằng bạn thực sự có thể có hướng dẫn về RAII (không phải là bạn có thể có trên mẫu thiết kế chẳng hạn). RAII là một cách nhìn vào tài nguyên hơn bất cứ thứ gì khác.

Ví dụ, tại thời điểm hiện tại tôi đang sử dụng mã hóa WinAPI và tôi đã viết lớp sau:

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; 

Lớp này không bao gồm phân công và sao chép ngữ nghĩa (tôi gỡ bỏ chúng để cung cấp một ví dụ rất nhỏ) do đó trở về theo giá trị, sẽ khiến các chốt đóng được hai lần.

Sau đây là cách nó được sử dụng: khai

lớp:

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

thành viên này được phân bổ nhưng tôi không bao giờ gọi ::CloseWindow(_window._handle) explicitely (nó sẽ được gọi khi trường hợp của Something đi ra khỏi phạm vi (như Something::~Something - >WindowHandle::WindowHandle ->::Close(_window._value)).

+3

Điều này cũng có thể được thực hiện bằng cách sử dụng 'boost :: shared_ptr' với một deallocator tùy chỉnh. Ví dụ: 'boost :: shared_ptr checked_handle (open_some_handle(), boost :: bind < void > (& :: CloseHandle, _1)); ' –

+1

Điểm tốt, nhưng tôi sẽ viết rằng với một số typedef-ing ít nhất. Tôi không thích sử dụng một lớp được gọi là "shared_ptr" cho một cái gì đó khác hơn là một con trỏ. Nó dẫn đến làm hỏng đường trong bảo trì. – utnapistim

+0

Trong một ý nghĩa, một tay cầm LÀ một con trỏ. Nó là một đại diện của một số tài nguyên bằng cách sử dụng một kiểu dữ liệu nguyên thủy (có nghĩa là, nó trỏ đến một tài nguyên bằng cách sử dụng một số nguyên - thường). –

2

Tài liệu tham khảo mà cá nhân tôi thấy hữu ích nhất về chủ đề của RAII là cuốn sách Exceptional C++ của Herb Sutter.

Nhiều chủ đề được đề cập trong cuốn sách đó được đề cập trong các bài viết của Guru of the Week bởi Sutter. Các bài viết đó có sẵn tại http://gotw.ca/gotw/index.htm.

+2

Chương nào của C++ vượt trội bao gồm chủ đề của RAII? – Javier