C++ 11范围退出后卫,一个好主意?

ron*_*nag 24 c++ c++11

我为C++ 11编写了一个小实用程序类,我将其用作范围保护,以便更轻松地处理异常安全和类似的事情.

看起来有点像黑客.但我很惊讶我没有在使用C++ 11功能的其他地方看到它.我认为boost与C++ 98类似.

但这是个好主意吗?或者是否有我错过的潜在问题?在boost或类似的解决方案中是否已经有类似的解决方案(使用C++ 11功能)?

    namespace detail 
    {
        template<typename T>
        class scope_exit : boost::noncopyable
        {
        public:         
            explicit scope_exit(T&& exitScope) : exitScope_(std::forward<T>(exitScope)){}
            ~scope_exit(){try{exitScope_();}catch(...){}}
        private:
            T exitScope_;
        };          

        template <typename T>
        scope_exit<T> create_scope_exit(T&& exitScope)
        {
            return scope_exit<T>(std::forward<T>(exitScope));
        }
    }


#define _UTILITY_EXIT_SCOPE_LINENAME_CAT(name, line) name##line
#define _UTILITY_EXIT_SCOPE_LINENAME(name, line) _UTILITY_EXIT_SCOPE_LINENAME_CAT(name, line)
#define UTILITY_SCOPE_EXIT(f) const auto& _UTILITY_EXIT_SCOPE_LINENAME(EXIT, __LINE__) = ::detail::create_scope_exit(f)
Run Code Online (Sandbox Code Playgroud)

并且使用了类似的东西.

int main () 
{
  ofstream myfile;
  myfile.open ("example.txt");
  UTILITY_SCOPE_EXIT([&]{myfile.close();}); // Make sure to close file even in case of exception
  myfile << "Writing this to a file.\n"; // Imagine this could throw
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

dir*_*tly 20

但这是个好主意吗?

当然.相关主题是RAII范例.

或者是否有我错过的潜在问题?

你不处理异常.

在boost或类似的情况下,是否已有类似的解决方案(具有C++ 0x功能)?

Alexandrescu 很久以前就提出了ScopeGuard.升压和std::tr1有一个东西叫scoped_ptrshared_ptr(与定制删除),它允许你完成眼前这个.


Gre*_*osz 17

为了记录,有Boost ScopeExit.


def*_*ode 9

范围守卫绝对是个好主意.我认为范围保护概念是异常安全的有力工具.如果您可以使用C++ 0x语法制作更安全,更清晰的Boost's ScopeExit版本,我认为这非常值得您花时间.

与Alexandrescu的ScopeGuard和Boost的ScopeExit类似,D编程语言也有这种东西的直接语法.D编程团队认为范围保护是一个很好的想法,他们直接将它添加到语言中(即它没有在库中实现).

例.

void foo( bool fail )
{
   scope(exit)
   {
      writeln("I'm always printed");
   }

   scope(success) writeln("The function exited normally");

   scope(error)
      writeln("The function exited with an exception.");

   if( fail )
      throw new Exception("Die Die Die!");
}
Run Code Online (Sandbox Code Playgroud)

基于范围的警卫并不是什么新鲜事.它的功能可以通过类析构函数(RAII和所有这些)轻松复制.也可以用try/finallyC#或Java 替换.哎呀,即使是pthreads提供了一个基本的范围守卫,叫做pthread_cleanup_push.

当你scope(*)在函数中有多个语句时,范围保护如此强大的原因.它的扩展性非常好,相反,try/finally它需要超级人力来管理两个以上的任何东西.


Aby*_*byx 5

如果用二元运算符替换create_scope_exit,我们可以删除括号:

class at_scope_exit
{
    template<typename F>
    struct scope_exit_fn_holder : boost::noncopyable
    {
        scope_exit_fn_holder(F&& f) : f(std::forward<F>(f)) {}

        F f;
        ~scope_exit_fn_holder() { f(); }
    };

    template<typename F>
    friend scope_exit_fn_holder<F> operator==(at_scope_exit, F&& f)
    {
        return scope_exit_fn_holder<F>(std::forward<F>(f));
    }
};
Run Code Online (Sandbox Code Playgroud)

用法:

auto atScopeExit = at_scope_exit() == [&]
{
    ...
};
Run Code Online (Sandbox Code Playgroud)

upd:
对应的宏:

#include <boost/preprocessor/cat.hpp>

#define AT_SCOPE_EXIT auto BOOST_PP_CAT(scopeExit_, __LINE__) = at_scope_exit() == [&]
#define AT_SCOPE_EXIT_EX(...) auto BOOST_PP_CAT(scopeExit_, __LINE__) = at_scope_exit() == [__VA_ARGS__]
Run Code Online (Sandbox Code Playgroud)