技术文章

了解最新技术文章

当前位置:首页>技术文章>技术文章
全部 146 常见问题 7 技术文章 139

think cell博客:穷人的例外

时间:2023-11-16   访问量:1033  标签: think-cell,测试自动化,think cell

假设我们正在执行一系列操作:

OpA();OpB();OpC();

现在,我们假设每个操作都可能失败,如果失败则返回 false(实际上,情况可能更复杂)。如果操作失败,我们希望中止并跳过所有后续操作。

实现此目的最直接的方法是通过嵌套if语句:

if(OpA()) {
    if(OpB()) {
        if(OpC()) {
            …
        }
    }}

如果操作的控制流程更复杂,嵌套if就不再那么有效了:

OpA();if( cond() ) OpB();OpC();…

会变成

if(OpA()) {
    if(!cond() || OpB()) {
        if(OpC()) {
            …
        }
    }}

第二个中的条件if处理故障以及操作的常规控制流。混合这两个问题并不理想。如果我们在其中加入一个循环,我们根本无法进行转换:

OpA();while( cond() ) OpB();OpC();…

没有与嵌套 if 等价的直接中止。

此问题的经典解决方案是例外:

try {
    if(!funcA()) throw abort();
    while( cond() ) {
        if(!funcB()) throw abort();
    }
    if(!funcC()) throw abort();
    …} catch(abort const&) {}

这是我们能做的最好的事情吗?

它确实有一些缺点。一是性能:当今 C++ 编译器中实现的异常抛出时速度很慢。另一个问题是,对于代码的读者来说,不能保证 sthrow abort()是唯一的abort异常来源。它们可能来自内部OpAOpB或者OpC为了向我们的读者保证情况并非如此,我们必须abort在本地声明:

struct abort{};try {
    if(!OpA()) throw abort();
    while( cond() ) {
        if(!OpB()) throw abort();
    }
    if(!OpC()) throw abort();
    …} catch(abort const&) {}

现在,读者仍然必须确保我们没有在不会被以下方法捕获的地方插入不同的异常catch

struct abort{};try {
    if(!OpA()) throw abort();
    while( cond() ) {
        if(!OpB()) throw abort2();
    }
    if(!OpC()) throw abort();
    …} catch(abort const&) {}

如果 的主体catch为空(并且只有这样),则有一种替代方法不会出现这些问题:如果操作是函数中发生的唯一事情,我们可以使用returns:

void operations() noexcept {
    if(!OpA()) return;
    while( cond() ) {
        if(!OpB()) return;
    }
    if(!OpC()) return;…}

operations已声明,noexcept因此很明显returns 是退出该函数的唯一代码路径。returns 都返回到函数外部的同一位置,这与可以在不同位置捕获的异常不同。

如果函数中的操作尚未隔离,我们可以将它们包装到立即执行的 lambda 中:

[&]() noexcept {
    if(!OpA()) return;
    while( cond() ) {
        if(!OpB()) return;
    }
    if(!OpC()) return;
    …}();

我称之为穷人的例外。对于某些情况,这实际上是一个很好的解决方案!


上一篇:think cell博客:可选<T const&>的优点

下一篇:think cell博客:规范代码的价值

发表评论:

评论记录:

未查询到任何数据!

免费通话

24小时免费咨询

请输入您的联系电话,座机请加区号

免费通话

微信扫一扫

微信联系
返回顶部