簡體   English   中英

是否有C ++標准類將變量設置為范圍出口處的值

[英]Is there a C++ standard class to set a variable to a value at scope exit

在成員函數的范圍內,我想暫時將成員變量設置為某個值。

然后,當此函數返回時,我想將此成員變量重置為給定的已知值。

為了防止異常和多次返回,我已經使用類似簡單的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看起來像( 在線演示 );

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()>根據保持函數的特定異常,為移動構造函數提供異常保證。 此處可找到此實現的示例
  • 這些異常規范與C ++提案和GSL實現一致
  • 我已經編輯了noexcept大部分動機,在C ++提案中找到了更多實質性細節
  • 析構函數的“通常”RAII語義,因此“范圍退出”功能適用; 它不會throw ,這也與析構函數的默認異常規范中的C ++ 11規范一致。 參見cppreferenceSO Q&AGotW#47HIC ++

可以找到其他實現;

你可以'濫用' shared_ptr

m_theVariableToChange = true;
std::shared_ptr<void> resetFalse(nullptr, [&](void*){ m_theVariableToChange = false; });

如果擔心使用void作為模板參數T ,我在C ++標准中發現了以下內容:

20.8.2.2§2:

... shared_ptr的模板參數T可以是不完整類型。

這表明T僅用作指針,因此使用void應該沒問題。

沒有標准版本。

CppGoreGuidelines支持庫( GSL )有一個通用版本, 最終稱為該庫,但該庫尚未生產。 絕對推薦的做法。

E.19 :如果沒有合適的資源句柄,則使用final_action對象表示清理

原因

finallytry / catch更簡潔,更難弄錯。

void f(int n)
{
    void* p = malloc(1, n);
    auto _ = finally([p] { free(p); });
    // ...
}

注意

finally並不像try / catch那樣凌亂,但它仍然是臨時的。 喜歡適當的資源管理對象。

類似的問題: 最簡單,最新的c ++ 11 ScopeGuard

在該線程上描述了一個用於調用任意函數的類似保護。 要解決您的問題,請調用一個重置您的變量的lambda。

例如,您的代碼的答案解決方案是:

scope_guard guard1 = [&]{ m_theVariableToChange = false; };

該線程的另一個答案指出,已經為C ++ 17標准化提出了類似的概念; 並且還提供了C ++ 03解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM