您可能知道这样的情况,您只想为一个变量(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
您知道哪些替代品(不错,简短,干净)?
答案 0 :(得分:2)
this thread上有三个不错的选择,实际上没有其他选择。
这些情况假设我们正在初始化一个对象;要按原样初始化引用,请将技术应用于std::reference_wrapper
或指针。
顺便说一句,我不会这么快打折您的第一个代码示例。它比所有其他选项都更简单,并且在C ++中,通常建议仅在特殊情况下使用异常-您不希望它们成为函数合同的正常部分。将它们用作快捷方式并不是惯用的。
换句话说,如果函数设计在查找失败的情况下不执行任何操作,则引发捕获是对函数的不必要的复杂化。您刚刚编写了一个更加丑陋的C样式错误处理版本。
at()
访问器的全部要点是,可以通过 not 捕获使您的函数保持简单-可以让异常传播到更通用的错误处理程序。