#include <functional> #include <utility> #include <type_traits> #include <iostream> class NonCopyable { public: NonCopyable() = default; ~NonCopyable() = default; NonCopyable(NonCopyable&&) = default; // allow move constructor private: NonCopyable(NonCopyable const& ) = delete; // copy constructor is hidden NonCopyable &operator=(NonCopyable const& ) = delete; // copy operator is hidden }; ///////////////////////////////////////////////////////// // ScopeExit template<typename FuncType> class ScopeExit : public NonCopyable { public: // constructor, use std::forward for perfect forwarding inline explicit ScopeExit(FuncType&& func) : _func(std::move(func)) {} inline explicit ScopeExit(FuncType const& func) : _func(func) {} // move constructor, move all content inline ScopeExit(ScopeExit&& rhs) : _func(std::move(rhs._func)) {} // destructor, if not dismiss then call func inline ~ScopeExit() { if (!_is_dismiss) _func(); } inline void Dismiss() { _is_dismiss = true; } private: FuncType _func; bool _is_dismiss = false; }; //////////////////////////////////////////////////////////// // ScopeExitCreator class ScopeExitCreator { public: template<typename FuncType> inline ScopeExit<typename std::decay<FuncType>::type> operator<<(FuncType&& func) { return ScopeExit<typename std::decay<FuncType>::type>(std::forward<FuncType>(func)); } }; #define TOKEN_CAT(x, y) x##y #define SCOPE_EXIT() auto TOKEN_CAT(scope_exit_, __LINE__) = ScopeExitCreator() << [&] #define SCOPE_EXIT_ARGS(args...) auto TOKEN_CAT(scope_exit_, __LINE__) = ScopeExitCreator() << [##args] #define SCOPE_EXIT_NAME(vname) auto vname = ScopeExitCreator() << [&]
看到这段代码,估计有人觉得很简单,但似乎自己如果让自己去写,却又不知道如何下手。不知道是否有人研究过Boost库的ScopeExit,其实该实现也是借鉴Boost库的。当然由于无法达到Boost库的开发者的水平,所以也只能从C++11的特性上入手完成这个功能。目的实际也很简单,就是为了处理那些函数可能有多个出口,并且无论是哪个出口都必须处理的操作,比如文件的关闭等。
但这么高深的代码又是如何运行的呢?
实际最重要的代码是在那几个宏的定义上,三个宏的定义,无一外乎有 auto 的声明,那么即是说,这里的代码如果展开到函数里,就是完成了一个对象的声明。还有代码中你会发现,对于传入的函数的调用是在析构函数调用的,那么理解起来就简单了许多,原来是在函数中声明了一个ScopeExit的对象,然后在函数退出时对象释放,从而会调用到ScopeExit的析构函数,执行了需要在函数退出时执行的代码。
那么,如果使用的不是C++11,是否也可以使用ScopeExit呢?因为目前这个是使用了functional库的呢。
目前是有一个方案是使用Boost库。其他的方法我暂时还未想到,待哪天如果有想到的话,就另行补上。
==========================================华丽的分割线=============================================================
这是发表博文后的几天后添加的内容,主要目的是为了兑现之前说有想到在c++98标准下的关于ScopeExit的方法。也只是一个无意中的尝试给了我一个小小的灵感。该尝试就是在函数中定义类。因为之前并不知道c++支持该方式的类的定义,也因此没有想到该方法,这也只是一个简单尝试过后的做法。
#define SCOPE_EXIT_98(T, para, code) \ class ScopeExit98{\ public:\ ScopeExit98(T para){ this->para = para; }\ ~ScopeExit98() { code;}\ private:\ T para;\ };\ ScopeExit98 scope_exit;
这个方法的使用方式如下:
#include <stdio.h> int main() { FILE *fp = fopen("a.test","a+"); SCOPE_EXIT_98(FILE*, fp, if(fp) fclose(fp); printf("test")) return 0; }该方法在预编译之后生成的代码如下:
int main() { FILE *fp = fopen("a.test","a+"); class ScopeExit98{ public: ScopeExit98(FILE* fp){ this->fp = fp; } ~ScopeExit98() { if(fp) fclose(fp); printf("test");} private: FILE* fp; };ScopeExit98 scope_exit(fp); return 0; }该方法实际一眼就可以发现很多不足。但对于一些简单的使用还是足够的。再加上配合一些c++宏的特性,应该还是可以满足大家的需求的。