[&]{
bool conditionA = executeStepA();
if (!conditionA) return; // break
bool conditionB = executeStepB();
if (!conditionB) return; // break
bool conditionC = executeStepC();
if (!conditionC) return; // break
}();
executeThisFunctionInAnyCase();
我们创建一个带有隐式引用捕获的匿名lambda函数,并运行它。其中的代码立即运行。
当它想要停止时,它只是返回。
然后,在它运行之后,我们运行executeThisFunctionInAnyCase。
在lambda内的Return是到块结束的断点。任何其他类型的流控制都可以工作。
异常被单独保留——如果您想捕获它们,请显式地执行。在抛出异常时要小心运行executeThisFunctionInAnyCase——如果executeThisFunctionInAnyCase可以在异常处理程序中抛出异常,则通常不希望运行它,因为这会导致混乱(这种混乱取决于语言)。
这种基于捕获的内联函数的一个很好的特性是您可以重构现有的代码。如果您的函数非常长,那么将其分解为组件是个好主意。
有一种变体适用于更多语言:
bool working = executeStepA();
working = working && executeStepB();
working = working && executeStepC();
executeThisFunctionInAnyCase();
你写的每一行都短路。代码可以在这些行之间注入,给你多个“在任何情况下”,或者你可以在执行步骤之间做if(working) {/* Code */},包括当且仅当你还没有跳出时应该运行的代码。
对于这个问题,一个好的解决方案应该在添加新的流量控制时具有鲁棒性。
在c++中,一个更好的解决方案是创建一个快速的scope_guard类:
#ifndef SCOPE_GUARD_H_INCLUDED_
#define SCOPE_GUARD_H_INCLUDED_
template<typename F>
struct scope_guard_t {
F f;
~scope_guard_t() { f(); }
};
template<typename F>
scope_guard_t<F> scope_guard( F&& f ) { return {std::forward<F>(f)}; }
#endif
然后在问题代码中:
auto scope = scope_guard( executeThisFunctionInAnyCase );
bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;
scope的析构函数自动运行executeThisFunctionInAnyCase。当您创建一个需要清理的非raii资源时,您可以在作用域末端注入更多这样的“资源”(给每个资源一个不同的名称)。它也可以取lambda,所以你可以操作局部变量。
更花哨的作用域保护可以支持终止析构函数中的调用(使用bool保护),阻止/允许复制和移动,并支持可以从内部上下文返回的类型擦除的“便携式”作用域保护。