• 2.2. RAII

    2.2. RAII

    智能指针的原理基于一个常见的习语叫做 RAII :资源申请即初始化。 智能指针只是这个习语的其中一例——当然是相当重要的一例。 智能指针确保在任何情况下,动态分配的内存都能得到正确释放,从而将开发人员从这项任务中解放了出来。 这包括程序因为异常而中断,原本用于释放内存的代码被跳过的场景。 用一个动态分配的对象的地址来初始化智能指针,在析构的时候释放内存,就确保了这一点。 因为析构函数总是会被执行的,这样所包含的内存也将总是会被释放。

    无论何时,一定得有第二条指令来释放之前另一条指令所分配的资源时,RAII 都是适用的。 许多的 C++ 应用程序都需要动态管理内存,因而智能指针是一种很重要的 RAII 类型。 不过 RAII 本身是适用于许多其它场景的。

    1. #include <windows.h>
    2.  
    3. class windows_handle
    4. {
    5. public:
    6. windows_handle(HANDLE h)
    7. : handle_(h)
    8. {
    9. }
    10.  
    11. ~windows_handle()
    12. {
    13. CloseHandle(handle_);
    14. }
    15.  
    16. HANDLE handle() const
    17. {
    18. return handle_;
    19. }
    20.  
    21. private:
    22. HANDLE handle_;
    23. };
    24.  
    25. int main()
    26. {
    27. windows_handle h(OpenProcess(PROCESS_SET_INFORMATION, FALSE, GetCurrentProcessId()));
    28. SetPriorityClass(h.handle(), HIGH_PRIORITY_CLASS);
    29. }
    • 下载源代码

    上面的例子中定义了一个名为 windows_handle 的类,它的析构函数调用了 CloseHandle() 函数。 这是一个 Windows API 函数,因而这个程序只能在 Windows 上运行。 在 Windows 上,许多资源在使用之前都要求打开。 这暗示着一旦资源不再使用之后就应该关闭。 windows_handle 类的机制能确保这一点。

    windows_handle 类的实例以一个句柄来初始化。 Windows 使用句柄来唯一的标识资源。 比如说,OpenProcess() 函数返回一个 HANDLE 类型的句柄,通过该句柄可以访问当前系统中的进程。 在示例代码中,访问的是进程自己——换句话说就是应用程序本身。

    我们通过这个返回的句柄提升了进程的优先级,这样它就能从调度器那里获得更多的 CPU 时间。 这里只是用于演示目的,并没什么实际的效应。 重要的一点是:通过 OpenProcess() 打开的资源不需要显示的调用 CloseHandle() 来关闭。 当然,应用程序终止时资源也会随之关闭。 然而,在更加复杂的应用程序里, windowshandle 类确保当一个资源不再使用时就能正确的关闭。 某个资源一旦离开了它的作用域——上例中 _h 的作用域在 main() 函数的末尾——它的析构函数会被自动的调用,相应的资源也就释放掉了。