使用可能抛出的表达式初始化 const 变量的推荐方法
Recommended way to initialize a const variable with an expression which might throw
你可能知道这样的情况,你只想用一个可能会失败(抛出)(例如container.at()
)的表达式分配给一个(const
)变量,这迫使你编写锅炉车牌代码:
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
- 你必须编写嵌套代码
您知道哪些(漂亮、简短、干净)替代品?
this thread 上有三个不错的选择,没有其他选择。
这些情况假设我们正在初始化一个对象;要按原样初始化引用,请将这些技术应用于 std::reference_wrapper
或指针。
顺便说一句,我不会这么快打折您的第一个代码示例。它比所有其他选项都简单,而且 C++ 中的一个常见建议是仅在异常情况下使用异常——您不希望它们成为函数契约的正常部分。将它们用作快捷方式不是惯用的。
换句话说,如果函数设计是在查找失败时什么也不做,那么抛出捕获对函数来说是一个不必要的复杂化。您刚刚编写了一个更丑陋的 C 风格错误处理版本。
at()
访问器的全部意义在于,您的函数可以通过 而不是 捕获来保持简单——异常可以被传播到更多通用错误处理程序。
你可能知道这样的情况,你只想用一个可能会失败(抛出)(例如container.at()
)的表达式分配给一个(const
)变量,这迫使你编写锅炉车牌代码:
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
- 你必须编写嵌套代码
您知道哪些(漂亮、简短、干净)替代品?
this thread 上有三个不错的选择,没有其他选择。
这些情况假设我们正在初始化一个对象;要按原样初始化引用,请将这些技术应用于 std::reference_wrapper
或指针。
顺便说一句,我不会这么快打折您的第一个代码示例。它比所有其他选项都简单,而且 C++ 中的一个常见建议是仅在异常情况下使用异常——您不希望它们成为函数契约的正常部分。将它们用作快捷方式不是惯用的。
换句话说,如果函数设计是在查找失败时什么也不做,那么抛出捕获对函数来说是一个不必要的复杂化。您刚刚编写了一个更丑陋的 C 风格错误处理版本。
at()
访问器的全部意义在于,您的函数可以通过 而不是 捕获来保持简单——异常可以被传播到更多通用错误处理程序。