C++ Scope Exit

最近在新的项目中帮忙时有对于SCOPE_EXIT的使用,对于这个能够在任何异常或者正常的时候都能执行,这好像是一个很牛逼的代码,激起了我的兴趣,于是瞅了一下这段代码:
#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++宏的特性,应该还是可以满足大家的需求的。


你可能感兴趣的:(C++,对象,scope,exit,functional)