将无状态 C++ 函数从里到外转换为有状态函数
Turning a stateless C++ function inside out, into a stateful one
我有一个 C++ 字符解析函数,它是在它自己的线程中写入 运行 的。它旨在每次需要处理更多数据时进行阻塞调用,并且在处理完所有数据之前永远不会 return 。像这样:
void runParser() {
while(true /*returns only when EOF encountered*/) {
//...
c = getNext(); //blocking call
//...
//...
c = getNext(); //blocking call
//...
//...
c = getNext(); //blocking call
//...
//...
//...
c = getNext(); //blocking call
//...
//...
c = getNext(); //blocking call
//...
//...50 more lines of code...
}
}
该函数在这种阻塞输入调用的实例中乱七八糟,在多种不同的情况下会有不同的解释。
我需要彻底改变功能。我不需要一个等待输入的单一函数,而是需要一个可以同步调用的函数,以便在新数据可用时处理每一位新数据。这意味着解析器代码需要从无状态转变为记住其状态。我需要尽快以最小的努力修改代码。
我初步的想法是修改函数如下:
用静态变量替换局部变量(因此函数保持状态)
用 return 语句替换阻塞调用,前面是 'current code position' 变量的赋值。
当新输入可用时,使用新数据再次调用函数。
函数的开头使用一个switch()
和一堆goto
跳回到它之前的位置。
任何人都可以提出一个更优雅、更简洁并且可能不涉及 goto 的替代方案吗?例如,C++ 是否还有其他任何可用于实现这些类型的 'stateful returns'?
要创建有状态函数,请使用仿函数。这是具有重载 () 运算符的 class 的对象。您在构造函数设置的初始状态下实例化此对象,并在调用 theObject () 期间调整状态,如前所述,该状态保存在对象内部。
不要使用static
:这些几乎是变相的全局变量。
有一项涉及 await 关键字的 Microsoft 提案可以使您的更改变得微不足道。但这还没有。
该提案到当前 C++ 代码的 "mechanical" 转换看起来像您的解决方案,除了我们制作 class 成员状态变量而不是静态状态变量和 operator()。他们也支持组合,但你不需要那个。
您可以通过将标签直接存储在 void pointer 指针和 goto 中来代替开关维护。
可以从 goto 解决方案进行重构。获取 returns 之间的每个 运行 代码,首先将其放入 lambda,然后放入方法。这可能很困难、不可能或毫无意义,但重构最终可能会取代 goto。您最终可能会得到一个状态机,可以说它比 spagetti goto 更容易理解。
真正干净的解决方案正在等待某些未来版本的 C++ 中的协程;对不起。您或许可以通过研究当今人们如何实现协程来获得灵感...
我有一个 C++ 字符解析函数,它是在它自己的线程中写入 运行 的。它旨在每次需要处理更多数据时进行阻塞调用,并且在处理完所有数据之前永远不会 return 。像这样:
void runParser() {
while(true /*returns only when EOF encountered*/) {
//...
c = getNext(); //blocking call
//...
//...
c = getNext(); //blocking call
//...
//...
c = getNext(); //blocking call
//...
//...
//...
c = getNext(); //blocking call
//...
//...
c = getNext(); //blocking call
//...
//...50 more lines of code...
}
}
该函数在这种阻塞输入调用的实例中乱七八糟,在多种不同的情况下会有不同的解释。
我需要彻底改变功能。我不需要一个等待输入的单一函数,而是需要一个可以同步调用的函数,以便在新数据可用时处理每一位新数据。这意味着解析器代码需要从无状态转变为记住其状态。我需要尽快以最小的努力修改代码。
我初步的想法是修改函数如下:
用静态变量替换局部变量(因此函数保持状态)
用 return 语句替换阻塞调用,前面是 'current code position' 变量的赋值。
当新输入可用时,使用新数据再次调用函数。
函数的开头使用一个
switch()
和一堆goto
跳回到它之前的位置。
任何人都可以提出一个更优雅、更简洁并且可能不涉及 goto 的替代方案吗?例如,C++ 是否还有其他任何可用于实现这些类型的 'stateful returns'?
要创建有状态函数,请使用仿函数。这是具有重载 () 运算符的 class 的对象。您在构造函数设置的初始状态下实例化此对象,并在调用 theObject () 期间调整状态,如前所述,该状态保存在对象内部。
不要使用static
:这些几乎是变相的全局变量。
有一项涉及 await 关键字的 Microsoft 提案可以使您的更改变得微不足道。但这还没有。
该提案到当前 C++ 代码的 "mechanical" 转换看起来像您的解决方案,除了我们制作 class 成员状态变量而不是静态状态变量和 operator()。他们也支持组合,但你不需要那个。
您可以通过将标签直接存储在 void pointer 指针和 goto 中来代替开关维护。
可以从 goto 解决方案进行重构。获取 returns 之间的每个 运行 代码,首先将其放入 lambda,然后放入方法。这可能很困难、不可能或毫无意义,但重构最终可能会取代 goto。您最终可能会得到一个状态机,可以说它比 spagetti goto 更容易理解。
真正干净的解决方案正在等待某些未来版本的 C++ 中的协程;对不起。您或许可以通过研究当今人们如何实现协程来获得灵感...