在成员函数的范围内,我想暂时将一个成员变量设置为一个特定的值.
然后,当该函数返回时,我想将此成员变量重置为给定的已知值.
为了避免异常和多个返回,我已经用类似类的简单的RAII来完成.它定义在成员函数的范围内.
void MyClass::MyMemberFunction() { struct SetBackToFalse { SetBackToFalse(bool* p): m_p(p) {} ~SetBackToFalse() {*m_p=false;} private: bool* m_p; }; m_theVariabletochange = true; SetBackToFalse resetFalse( &m_theVariabletochange ); // Will reset the variable to false. // Function body that may throw. }
看起来很常见,我想知道是否有这样的模板类在C标准库中执行此操作?
解决方法
还没有(有这方面的建议).但实现一个通用的是简单的;
struct scope_exit { std::function<void()> f_; explicit scope_exit(std::function<void()> f) noexcept : f_(std::move(f)) {} ~scope_exit() { if (f_) f_(); } }; // ... m_theVariabletochange = true; scope_exit resetFalse([&m_theVariabletochange]() { m_theVariabletochange = false; });
为了简单起见,我已经编辑了复制和移动构造函数等…
将它们标记为= delete将使上述成为最小的解决方案.进一步;如果需要,可以允许移动,但应禁止复制.
更完整的scope_exit看起来像(online demo here);
template <typename F> struct scope_exit { F f_; bool run_; explicit scope_exit(F f) noexcept : f_(std::move(f)),run_(true) {} scope_exit(scope_exit&& rhs) noexcept : f_((rhs.run_ = false,std::move(rhs.f_))),run_(true) {} ~scope_exit() { if (run_) f_(); // RAII semantics apply,expected not to throw } // "in place" construction expected,no default ctor provided either // also unclear what should be done with the old functor,should it // be called since it is no longer needed,or not since *this is not // going out of scope just yet... scope_exit& operator=(scope_exit&& rhs) = delete; // to be explicit... scope_exit(scope_exit const&) = delete; scope_exit& operator=(scope_exit const&) = delete; }; template <typename F> scope_exit<F> make_scope_exit(F&& f) noexcept { return scope_exit<F>{ std::forward<F>(f) }; }
执行情况说明
> std :: function< void()>可以用来擦除函子的类型.的std ::功能<无效()>基于所保留的功能的异常特定,在移动构造函数上提供异常保证.此实现的示例见here
>这些异常规范与C提议和GSL实现是一致的
>我已经修改了大部分的noexcept的动机,更多的细节在C++ proposal发现
>析构函数的“通常”RAII语义,因此“范围退出”功能适用;它不会抛出,这也符合关于析构函数的默认异常规范的C 11规范.参见cppreference,SO Q&A,GotW#47和HIC++
可以找到其他实现;
> The C++ proposal上述和its revision (as of this writing)
> Boost.ScopeExit
> The Microsoft GSL implementation