我刚刚了解了Scope Guard C ++习语。不幸的是,我找不到任何好的实现。
有人能指出我在C ++中使用一些优秀且可用的Scope Guard实现吗?
谢谢,Boda Cydo。
答案 0 :(得分:15)
最初的ScopeGuard课程由Andrei Alexandrescu和Petru Marginean列入this Dr. Dobb's article。稍微改进的版本,以及Joshua Lehrer的一些更改可用here。 (Lehrer的版本是我在我的项目中使用的版本。)它也包含在Loki库中。
Boost现在有一个ScopeExit库,它比ScopeGuard更强大(因为它可以执行任意代码,而ScopeGuard只能调用一个预先存在的函数)。
编辑:尽管如此,Scope Guard实际上只是RAII的一个特定应用,所以你真的应该至少理解如何实现它的概念。
答案 1 :(得分:8)
ScopeGuard已经包含在Loki库中(由Andrei Alexandrescu在Modern C ++ Design中做广告,我相信你已经听说过这本好书),并且已经足够成熟,可以用于生产代码,伊莫。
为了清楚起见:我们正在讨论使用RAII编写异常安全代码。
附加阅读(在StackOverflow上): Does ScopeGuard use really lead to better code?
答案 2 :(得分:4)
Folly库(来自facebook的开源)也提供了一个实现(因为他们雇佣了A.A.,这并不奇怪):
https://github.com/facebook/folly/blob/master/folly/ScopeGuard.h
我认为这和这里提到的MNMLSTC实现都值得考虑。
答案 3 :(得分:0)
“Scope Guard”对象只是更广泛的RAII成语的一个实例。
并没有单一的实施。这是C ++程序员必须理解的东西,而不仅仅是复制/粘贴。幸运的是,实施起来也很简单。
您创建一个代表某种资源的类。当类被实例化(由其构造函数之一)时,它应该获取资源,并在失败时抛出异常。当类被销毁时,它应该处理资源,执行所有必要的清理。
而且......就是这样。您还必须处理复制构造函数和赋值运算符(通过克隆资源或将这两个函数设为私有,因此它们永远不会被调用)。
你不需要找到“一个好的实现”,因为你将自己编写几十个和几十个不同的实现。它们写起来很简单,并且它们不能轻易地被重用,因为每个都包含不同类型的资源。
答案 4 :(得分:0)
有人建议将scope_guard添加到标准库中。您可以阅读该论文,其中包括您可以复制/粘贴的示例实现here。有关实施,请参见第9.1节。
答案 5 :(得分:0)
答案 6 :(得分:0)
让我提供一个基本的 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
可调用对象上增加零内存开销,因为我们不需要将它保存在可重置方式,因为我们不需要移动构造函数,因为我们得到了类模板参数推导。
语言变得多么富有表现力的一个很好的例子。谢谢委员!