如何在查找函数 returns 引用时编写干净的 try/catch 块?

how to write clean try/catch block when find function returns a reference?

我有一些代码如下所示:

const SomeType & elt = x.find();
try {
    // ... do something with elt ...
} catch (...) {
    // handle processing exception
}

它有效,但由于环境不断变化,现在 find() 方法可能会抛出“未找到”异常,我需要捕获该异常。

我想写的是

try {
    const SomeType & elt = x.find();
} catch (...) {
    // handle "not found" exception
    return;
}
try {
    // ... do something with elt ...
} catch (...) {
    // handle processing exception
}

但这当然行不通,因为在到达其处理块时,elt 已不在范围内。我无法将其重新排列为

const SomeType & elt;
try {
    elt = x.find();
} catch (...) {
    // handle "not found" exception
    return;
}

因为 C++ 中的引用类型当然不允许未初始化。所以我剩下的选择是暂时将 elt 设置为对类型 SomeType 的虚拟对象的引用,我不想这样做,或者嵌套 try/catch 块,像这样:

try {
    const SomeType & elt = x.find();
    try {
        // ... do something with elt ...
    } catch (...) {
        // handle processing exception
    }
} catch (...) {
    // handle "not found" exception
}

我也不喜欢这样:嵌套令人困惑,而且我不喜欢“未找到”异常处理程序最后隐藏在那里的方式。

谁能想出更好的安排方式? (当然,在 C 中,我们只是让 find 函数 return 在未找到的情况下有一个空指针,并以这种方式处理它,但我想尽量不要成为一个旧的当我写 C++ 时是 C 程序员,无论如何 x.find() 已经设置为 return 一个引用,而不是一个指针。)

拆分成另一个函数:

void func1()
{
    try {
        const SomeType & elt = x.find();
        func2(elt);
    } catch (...) {
        // handle "not found" exception
    }
}

void funct2(const SomeType & elt)
{
    try {
        // ... do something with elt ...
    } catch (...) {
        // handle processing exception
    }
}

尽管总的来说我发现您的界面有点令人不安,因为首先需要所有这些 try/catch 块。不幸的是,很难用如此少的信息就如何改进总体风格提供建议。

它不会合每个人的口味(顺便说一下,行为 定义的),但您可以使用

#include <functional>
std::reference_wrapper<const SomeType> elt = elt;
try {
    elt = x.find();
} catch (...) {
    // handle "not found" exception
    return;
}

可以说 elt 的设置本身是对 std::reference_wrapper 的滥用,它的默认构造函数和移动构造函数被设计删除:我正在规避它。

本质上 std::refernce_wrapper 是一个隐藏在引擎盖下的指针,但您可以重新绑定它,这基本上就是您想要在此处执行的操作。

如果异常不同,您可以使用相同的 try 块:

try {
    const SomeType& elt = x.find();
    // ... do something with elt ...
} catch (const NotFoundException&) {
    // handle "not found" exception
} catch (...) {
    // handle processing exception
}

else rebinding reference 是不允许的,但是一般可以用指针或者std::reference_wrapper来模拟,

和可选引用(std 中不允许,但 boost 允许)可能由指针或 std::optional<std::reference_wrapper<T>>.

模拟

所以:

const SomeType* eltPtr = nullptr; 
try {
    eltPtr = &x.find();
} catch (const NotFoundException&) {
    // handle "not found" exception
    return;
}
const SomeType& elt = *eltPtr; 
try {
    // ... do something with elt ...
} catch (...) {
    // handle processing exception
}