是否有 C++ 标准 class 将变量设置为范围退出时的值
Is there a C++ standard class to set a variable to a value at scope exit
在一个成员函数的范围内,我想临时设置一个成员变量为某个值。
那么,当这个函数returns的时候,我想把这个成员变量重新设置为一个给定的已知值
为了防止异常和多重 returns,我已经使用像 class 这样的简单 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++ 标准库中是否有这样的模板 class 这样做?
还没有(已经有这方面的提议)。但是实现一个通用的很简单;
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::function<void()>
根据持有函数的特定异常为移动构造函数提供异常保证。已找到此实现的示例 here
- 这些异常规范与 C++ 提议和 GSL 实现一致
- 我已经编辑了
noexcept
的大部分动机,更多详细信息可以在 C++ proposal 中找到
- 析构函数的"usual"RAII语义,因此"scope exit"函数适用;它不会
throw
,这也符合 C++11 规范关于析构函数的默认异常规范。参见 cppreference, SO Q&A, GotW#47 and HIC++
可以找到其他实现;
您可以 'abuse' shared_ptr
为此:
m_theVariableToChange = true;
std::shared_ptr<void> resetFalse(nullptr, [&](void*){ m_theVariableToChange = false; });
如果担心使用 void
作为模板参数 T
,我在 C++ 标准中发现了以下内容:
20.8.2.2§2:
... The template parameter T of shared_ptr may be an incomplete type.
这表明T
仅用作指针,因此使用void
应该没问题。
没有标准版本。
CppGoreGuidelines Support Library (GSL) has a generalized version of this called finally 但是那个库还不是生产质量。绝对推荐的做法。
E.19:如果没有合适的资源句柄可用,使用final_action
对象表示清理
原因
finally
比 try
/catch
.
更简洁,更不容易出错
例子
void f(int n)
{
void* p = malloc(1, n);
auto _ = finally([p] { free(p); });
// ...
}
备注
finally
不像try
/catch
那么乱,但它仍然是临时的。
优先选择合适的资源管理对象。
类似问题:The simplest and neatest c++11 ScopeGuard
在该线程上描述了一个用于调用任意函数的类似守卫。要解决您的问题,请调用一个 lambda 来重置您的变量。
例如,this answer 中针对您的代码的解决方案是:
scope_guard guard1 = [&]{ m_theVariableToChange = false; };
该线程的另一个答案指出,已为 C++17 标准化提出了类似的概念;并且还提供了一个 C++03 解决方案。
在一个成员函数的范围内,我想临时设置一个成员变量为某个值。
那么,当这个函数returns的时候,我想把这个成员变量重新设置为一个给定的已知值
为了防止异常和多重 returns,我已经使用像 class 这样的简单 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++ 标准库中是否有这样的模板 class 这样做?
还没有(已经有这方面的提议)。但是实现一个通用的很简单;
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::function<void()>
根据持有函数的特定异常为移动构造函数提供异常保证。已找到此实现的示例 here- 这些异常规范与 C++ 提议和 GSL 实现一致
- 我已经编辑了
noexcept
的大部分动机,更多详细信息可以在 C++ proposal 中找到
- 析构函数的"usual"RAII语义,因此"scope exit"函数适用;它不会
throw
,这也符合 C++11 规范关于析构函数的默认异常规范。参见 cppreference, SO Q&A, GotW#47 and HIC++
可以找到其他实现;
您可以 'abuse' shared_ptr
为此:
m_theVariableToChange = true;
std::shared_ptr<void> resetFalse(nullptr, [&](void*){ m_theVariableToChange = false; });
如果担心使用 void
作为模板参数 T
,我在 C++ 标准中发现了以下内容:
20.8.2.2§2:
... The template parameter T of shared_ptr may be an incomplete type.
这表明T
仅用作指针,因此使用void
应该没问题。
没有标准版本。
CppGoreGuidelines Support Library (GSL) has a generalized version of this called finally 但是那个库还不是生产质量。绝对推荐的做法。
E.19:如果没有合适的资源句柄可用,使用final_action
对象表示清理
原因
finally
比 try
/catch
.
例子
void f(int n)
{
void* p = malloc(1, n);
auto _ = finally([p] { free(p); });
// ...
}
备注
finally
不像try
/catch
那么乱,但它仍然是临时的。
优先选择合适的资源管理对象。
类似问题:The simplest and neatest c++11 ScopeGuard
在该线程上描述了一个用于调用任意函数的类似守卫。要解决您的问题,请调用一个 lambda 来重置您的变量。
例如,this answer 中针对您的代码的解决方案是:
scope_guard guard1 = [&]{ m_theVariableToChange = false; };
该线程的另一个答案指出,已为 C++17 标准化提出了类似的概念;并且还提供了一个 C++03 解决方案。