如何阻止访客

How to stop a visitor?

本文关键字:访客 何阻止      更新时间:2023-10-16

一个典型的访问者模式设计如下:

template<class Visitor>
void processData(Visitor& visitor)
{
    // maybe in sequence
    visitor.process(...);
    visitor.process(...);
    ...
    // may have expensive computations
    doExpensiveComputations();
    // or in some loops
    for (...)
        visitor.process(...);
    // or in some recursive calls
    recursive(visitor);
}

当访问者对其余数据失去兴趣(例如找到答案)时,如何尽快返回?

请注意,任何需要更改设计的内容都是不可接受的,例如,我不想强迫Visitor::process返回一个值,并每次检查它。

我真正想做的是强制堆栈展开,我可以使用异常,但有人告诉我,对控制流使用异常是反模式的。

我认为Boost.Coroutine可能会有所帮助,但它仍然使用异常来进行堆栈展开。。。

我目前所做的如下:

struct Visitor
{
    void process(T data)
    {
        if (stopped)
            return;
        ...
    }
    ...
};

但这仍然会影响执行,以及我们不需要的昂贵计算。

既然c++中除了可以展开堆栈的异常之外,没有其他可移植的方法,那么我应该在这里使用异常来控制流吗?

请注意,任何需要更改设计的内容都是不可接受的,例如,我不想强迫Visitor::process返回一个值,并每次检查它。

通过";设计;在这种情况下,我认为你的意思是";访问者的签名::process";。

我真正想做的是强制堆栈展开,我可以使用异常,但有人告诉我,对控制流使用异常是反模式的。

我应该在这里使用控制流的异常吗?

在这里使用异常不一定是反模式(就像它是一个"中断执行"系统一样——这可能是错误也可能不是错误)。

我曾经遇到过这种情况("使用异常来发出错误以外的信号"),我使用了一个thowable类型(它不是直接或间接继承自std::exception)。我的指导方针是";如果它继承自std::exception,则为错误;否则,它是处理不继续的信号";。

以这个实现为例:

struct ProcessingInterrupted final {}; // <--- thin/empty implementation
                                       // not inheriting std exceptions
                                       // and not inheritable
struct Visitor
{
    void process(T data)
    {
        if(worldEnds)
            throw ProcessingInterrupted{};
        // ...
    }
    ...
};
template<class Visitor>
bool process(Visitor& visitor)
{
    try
    {
        processData(visitor); // taken from your example
        return true;
    }
    catch(const ProcessingInterrupted&)
    {
        return false;
    }
}
// client code
Visitor v;
/* auto success = */ process(v);

这样,ProcessingInterrupted类型告诉您正在发生的事情("处理被中断"),并且客户端代码(对于示例中的processData和我的过程)看起来是最小化的,并且具有明确定义的目的。

您可以禁用boost.coroutine的堆栈展开(类属性)示例/cpp03/asymmetric/same_fring.cpp显示了递归遍历树的一种变体——也许它会对您有所帮助。