【问题标题】:Where can I find a good Scope Guard implementation for my C++ projects?我在哪里可以为我的 C++ 项目找到一个好的 Scope Guard 实现?
【发布时间】:2010-08-12 11:56:50
【问题描述】:

我最近刚刚了解了 Scope Guard C++ 习语。不幸的是,我找不到任何好的实现。

谁能给我指点 C++ 中一些好的和可用的 Scope Guard 实现?

谢谢,博达·赛多。

【问题讨论】:

  • 以前从未听说过这个 - 其他人骗我,请参阅en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Scope_Guard。恕我直言,这似乎不太有用。而且实现起来很简单——你不需要“找到一个实现”。
  • @Neil:很有趣,因为它与我对 RAII 相关习语的期望大不相同。我确实想知道成功执行后谁来处理资源。
  • 据我所知,智能指针只有delete,但使用范围保护你也可以delete []freefclose()close_my_object等。所以我认为它更好.如果我错了,请纠正我。
  • 智能指针不必只调用delete。见boost.org/doc/libs/1_43_0/libs/smart_ptr/…。虽然我个人认为 Scope Guard 对于 close_my_object 之类的情况更清晰。
  • 我真的推荐Boost's Scope Exit,他们做得很好。

标签: c++ scope guard


【解决方案1】:

最初的 ScopeGuard 类包含在 Andrei Alexandrescu 和 Petru Marginean 的 this Dr. Dobb's article 中。 here 提供了一个略微改进的版本,其中包含 Joshua Lehrer 的一些更改。 (Lehrer 的版本是我在项目中使用的版本。)它也包含在 Loki 库中。

Boost 现在有一个ScopeExit 库,它比 ScopeGuard 更强大(因为它可以执行任意代码,而 ScopeGuard 只能调用一个预先存在的函数)。

编辑:话虽如此,Scope Guard 实际上只是 RAII 的一种特定应用,所以你真的应该至少了解如何实现它的概念。

【讨论】:

  • 自从写了这个答案之后,C++11 就出来了,在它之后 - 一个新的 ScopeGuard,比以前好得多;考虑弃用您的答案,转而支持@MikeEllery 的this one
【解决方案2】:

ScopeGuard 已包含在 Loki 库中(在 Andrei Alexandrescu 的 Modern C++ Design 中进行了宣传,我相信您已经听说过这本好书),并且已经足够成熟,可以在生产代码中使用,imo。

明确一点:我们正在讨论使用 RAII 编写异常安全代码。

补充阅读(在 StackOverflow 上): Does ScopeGuard use really lead to better code?

【讨论】:

  • 是的,我听说过现代 C++ 设计。但是我没有读过这本书,因为它很难理解!我也许能理解每一页中的一句话。 :)
  • @boda 其实我觉得写的比较清楚。我认为问题在于他并不总是完全明确地说明他所说的做事的动机,而是希望你了解它们。
  • 一开始我发现现代 C++ 设计很难,但在阅读了有关 Haskell 的教程并重新阅读了有关模板的内容后,我理解得很好,回想起来我不知道他应该做些什么不同的事情。继续回来看,这本书真的很好
  • Alexandrescu 的新的 C++11-ish ScopeGuard 现在是愚蠢的一部分,请参阅@MikeEllery 的this answer
【解决方案3】:

Folly 库(来自 facebook 的开源)也提供了一个实现(这并不奇怪,因为他们采用了 A.A.):

https://github.com/facebook/folly/blob/master/folly/ScopeGuard.h

我认为这个和这里提到的 MNMLSTC 实现都值得考虑。

【讨论】:

    【解决方案4】:

    让我提供一个基本的 C++20 版本。

    #include <concepts>
    #include <type_traits>
    
    template <std::invocable Cleanup>
    class [[nodiscard]] scope_guard
    {
        Cleanup d;
    public:
        scope_guard(Cleanup&& d) : d{std::forward<Cleanup>(d)} {}
        scope_guard(const scope_guard&) = delete;
    
        ~scope_guard(){d();}
    };
    
    // allow construction from plain function
    template <typename F>
    scope_guard(F&&) -> scope_guard<std::decay_t<F>>;
    

    请注意,除非我们需要移动 scope_guard,否则它会在 Cleanup 可调用对象上增加零内存开销,因为我们不需要以可重置的方式保存它,因为我们不需要移动构造函数,因为我们得到了类模板参数推导。

    语言表达能力的一个很好的例子。谢谢组委会!

    【讨论】:

      【解决方案5】:

      “Scope Guard”对象只是更广泛的RAII 惯用语的一个实例。

      并且没有单一的实现。这是 C++ 程序员必须理解的东西,而不仅仅是复制/粘贴。幸运的是,实现起来也很简单。

      你创建了一个代表某种资源的类。当类被实例化(通过其构造函数之一)时,它应该获取资源,如果失败则抛出异常。当类被销毁时,它应该处理资源,执行所有必要的清理。

      然后……就是这样。您还必须处理复制构造函数和赋值运算符(通过克隆资源或将这两个函数设为私有,这样它们就不会被调用)。

      您不需要找到“一个好的实现”,因为您将自己编写几十个不同的实现。它们写起来很简单,而且它们不容易被重用,因为每个都包装了不同类型的资源。

      【讨论】:

      • 谢谢,jalf,我会尝试自己写。男孩,这对我来说会是一个困难的练习吗?我从来没有想过写这么复杂的代码!
      • 一个好的 Scope Guard 类的优点是它可以很容易地在清理时调用任意代码,而不必自己编写几十个不同的实现。
      【解决方案6】:

      有人提议将 scope_guard 添加到标准库中。你可以阅读这篇论文,其中包括一个可以复制/粘贴的示例实现,here。实现见第 9.1 节。

      【讨论】:

        【解决方案7】:

        MNMLSTC core 有一个modern C++11 implementation 的作用域保护习语。

        【讨论】:

          猜你喜欢
          • 2012-03-18
          • 1970-01-01
          • 1970-01-01
          • 2011-03-11
          • 2019-07-31
          • 1970-01-01
          • 2013-12-29
          • 1970-01-01
          • 2011-07-03
          相关资源
          最近更新 更多