scope_exit思想是c++设计新思维的作者Alex ...,后缀是什么的忘记了,当时第一次看到有这个东西,并认真的研究了一下,研究完了,感觉是热血沸腾的。早起的实现版本,由于c++0x并未支持模板可变参数列表,所以只能用很烦人的宏来取代。
由于c++11引入了模板可变参数列表,多个参数替换的宏,只需要一行代码改变为几个点,就一切ok了。
本身scope_exit的主要应用场景是,当退出作用域的时候自动执行相应的操作。在我们编程的过程中,通常会写一些资源管理的类,来自动管理相关的资源,如windows的HANDLE,HWND等等。
具体的写法,估计因人而异,这里就不再罗列,今天重点讲讲通过scope_exit思想联合c++11来实现一个HANDLE的自动管理类。
上代码:
/*
* \brief: scope resource.
*/
#if !defined(scope_resx_h_)
#define scope_resx_h_
#include <functional>
#include <memory>
struct scope_base {
virtual ~scope_base() {}
};
template<typename Fun, typename ... ARGS>
struct scope_resx : public scope_base {
scope_resx(Fun f, ARGS ... args)
: func_(std::bind(f, args ...))
{
}
virtual ~scope_resx() {
func_();
}
private:
typedef void (*func)(ARGS ... args);
std::function<void()> func_;
};
#define scope_1(func, arg) \
scope_resx<decltype(func), decltype(arg)>(func, arg)
#define scope_1_type(func, arg) \
decltype(scope_1(func, arg))
#define scope_2(func, arg1, arg2) \
scope_resx<decltype(func), decltype(arg1), decltype(arg2)>(func, arg1, arg2)
#define scope_2_type(func, arg1, arg2) \
decltype(scope_2(func, arg1, arg2))
typedef std::shared_ptr<scope_base> scope_ptr;
#endif // scope_resx_h_
针对上面的代码,进行以下几点总结:
1. 通过函数对象保存所有的函数参数状态,通过std::bind()来进行绑定,并赋值给函数对象。这样避免了对所有的参数进行保存,通过函数对象本身就可以携带状态来处理函数的参数。
2. 通过将scope_resx的基类设定为scope_base来便于使用智能指针对于类型的管理,基于基类的指针可以指向任何派生类。如果不适用这个技巧,需要下面的宏scope_1_type进行类型推导出模板的类型,非常ugly。而通过基类的方式,自然就解决了这问题。
3. 采用宏来替代书写scope_resx<...>中的...部分内容,通过自动推导类型关键字decltype来自动推导出所有类型,避免了类型的定义。
针对windows的HANDLE的代码可以这样写:
#include <scope_resx.h>
#include <windows.h>
#define scopeHandle(handle) scope_1(CloseHandle, handle)
实际的使用如下:
void test() {
HANDLE hd = CreateFile(...);
scope_ptr autohandle(new scopeHandle(hd));
//...
//...
}
显然,非常优雅的就实现了handle的管理。