建议使用可能会引发的表达式初始化const变量的方法

时间:2018-08-02 09:40:28

标签: c++ exception-handling const

您可能知道这样的情况,您只想为一个变量(const)赋值,该变量可能会失败(抛出)(例如container.at()),从而迫使您编写样板代码:

void foo(const string &key) {
    auto it = data_store.find(key);
    if (it == data_store.end()) {
        return;
    }
    const auto & element = it->second;
    ...
    go on with `element`...
    ...
}

在Python中,您可以编写如下代码:

def foo(name):
    try:
        element = data_store[key]
    except KeyError:
        return
    ..
    go on with `element`
    ..

.. with的噪音较小,因为您不会仅仅为了检查是否存在而引入了无用的额外it

如果C ++的try不引入变量范围,则可以使用at()

void foo(const string &key) {
    try {
        const auto & element = data_store.at(key);
    } catch (const out_of_range &) {
        return;
    }
    ...
    go on with `element`...
    ...
}

如果不想放弃 constness 并保持代码整洁,该怎么办?

如果lambda只能具有try / catch正文,则可以编写

void foo(const string &key) {
    const auto & element = [&] () -> T try {
        return data_store.at(key);
    } catch () {
        return;
    } ();
    ...
    go on with `element`...
    ...
}

对类似问题的一些答案建议在所有代码中使用try / catch块:

void foo(const string &key) {
    try {
        const auto & element = data_store.at(key);
        ...
        go on with `element`...
        ...
    } catch (const out_of_range &) {
        return;
    } catch (some other exception) {
        ...
    } catch (some other exception) {
        ...
    }
}

但是我不喜欢这样做有三个原因:

  • at()catch块之间没有视觉关联
  • 可能还有一些代码需要您处理out_of_range
  • 您必须编写嵌套代码

您知道哪些替代品(不错,简短,干净)?

1 个答案:

答案 0 :(得分:2)

this thread上有三个不错的选择,实际上没有其他选择。

这些情况假设我们正在初始化一个对象;要按原样初始化引用,请将技术应用于std::reference_wrapper或指针。


顺便说一句,我不会这么快打折您的第一个代码示例。它比所有其他选项都更简单,并且在C ++中,通常建议仅在特殊情况下使用异常-您不希望它们成为函数合同的正常部分。将它们用作快捷方式并不是惯用的。

换句话说,如果函数设计在查找失败的情况下不执行任何操作,则引发捕获是对函数的不必要的复杂化。您刚刚编写了一个更加丑陋的C样式错误处理版本。

at()访问器的全部要点是,可以通过 not 捕获使您的函数保持简单-可以让异常传播到更通用的错误处理程序。