18

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

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

谢谢,博达赛多。

4

7 回答 7

15

最初的 ScopeGuard 类包含在Andrei Alexandrescu 和 Petru Marginean的 Dobb 博士的这篇文章中。稍微改进的版本,与 Joshua Lehrer 的一些更改可在此处获得。(Lehrer 的版本是我在项目中使用的版本。)它也包含在Loki库中。

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

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

于 2010-08-12T17:12:53.253 回答
8

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

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

附加阅读(在 StackOverflow 上): ScopeGuard 的使用真的会带来更好的代码吗?

于 2010-08-12T12:03:22.080 回答
4

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

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

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

于 2015-06-04T19:03:45.347 回答
1

让我提供一个基本的 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它会比 callable 增加零内存开销Cleanup,因为我们不需要以可重置的方式保存它,因为我们不需要移动构造函数,因为我们得到了类模板参数推导。

语言变得多么富有表现力的一个很好的例子。谢谢组委会!

于 2021-03-03T19:25:18.297 回答
0

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

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

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

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

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

于 2010-08-12T12:11:40.110 回答
0

有一个建议将 scope_guard 添加到标准库中。您可以在此处阅读该论文,其中包括一个您可以复制/粘贴的示例实现。实施见第 9.1 节。

于 2014-05-03T02:10:20.843 回答
0

MNMLSTC 核心具有作用域保护习语的现代 C++11 实现

于 2014-08-14T08:17:37.030 回答