#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++宏的特性,应该还是可以满足大家的需求的。