try 中变量的 C++ 作用域
C++ scope of variables inside try
考虑这段代码:
try {
const Asdf &a = map1.at(index1);
const Bsdf &b = map2.at(index2);
} catch(std::out_of_range&) {
return false;
}
// <code>
std::cout<<a[b[42]]; // May throw std::out_of_range which should not be caught here.
return true;
<code>
使用 a 和 b。我有两个选择:
- 将
<code>
放入try块
- 在 try 块中获取指针,然后取消引用它们
第一个选项是错误的,因为如果 <code>
抛出 std::out_of_range
函数将 return false,只有在地图查找失败时才会发生这种情况。
第二个选项可能有点难看:
const Asdf *a;
const Bsdf *b;
try {
a = &map1.at(index1); // What?
b = &map2.at(index2);
} catch(std::out_of_range&) {
return false;
}
std::cout << (*a)[(*b)[42]];
return true;
有没有更好的方法? Python 中的 try-except-else 之类的东西会很好,但在 C++ 中不存在。
一种解决方法是确保地图确实包含该项目。它增加了开销,但在我所知道的许多更糟糕的方法中并没有那么糟糕。
try{
map1.at(index1);
map2.at(index2);
}catch(std::out_of_range&){
return false;
}
const Asdf &a=map1.at(index1);
const Bsdf &b=map2.at(index2);
或者如果以更好的方式编写(抱歉,没有性能提升,只有可读性),除非您想牺牲 const
引用。
if(map1.find(index1) == map1.end() || map2.find(index2) == map2.end()) return false;
const Asdf &a=map1.at(index1);
const Bsdf &b=map2.at(index2);
您也可以使用 std::map::const_iterator 而无需 try-catch 块。
std::map::const_iterator a = map1.find(index1);
if(a == map1.end()) return false;
std::map::const_iterator b = map1.find(index2);
if(b == map2.end()) return false;
对只读 a->second
和 b->second
做任何事情。
解决方案 1:
为什么将代码包含在 try catch 中,将其嵌入到自己的 try catch 块中以区分两种情况?
try {
const Asdf &a = map1.at(index1);
const Bsdf &b = map2.at(index2);
try {
// <code>
std::cout<<a[b[42]]; // May throw std::out_of_range which should not be caught here.
} catch (std::out_of_range&) {}
} catch(std::out_of_range&) {
return false;
}
return true;
但是当然,在这种方法中,您不能将 out_of_range
转发到函数外部,而 out_of_range
会在 <code>
.
中发生
解决方案 2:
另一种方法是使用 map::count()
简单地检查键的存在,而不需要异常捕获:
if (map1.count(index1)==0 || map2.count(index2)==0) {
return false;
}
const Asdf &a = map1.at(index1);
const Bsdf &b = map2.at(index2);
// <code>
std::cout<<a[b[42]];
return true;
不需要做任何异常处理。 std::map::find
,给定一个键,会给你一个迭代器。如果地图中不存在该元素,则 find
将 return end
迭代器(即 map.end()
)。
取消引用迭代器时,您将收到一对值。第一个是键,第二个是对象。
auto aIt = map1.find(index1);
auto bIt = map2.find(index2);
if(aIt == map1.end() || bIt == map2.end())
{
return false;
}
const Asdf &a = aIt->second;
const Bsdf &b = bIt->second;
std::cout << a[b[42]];
return true;
请注意,C++ 中的迭代器是这样定义的,即 begin
迭代器位于开始位置,而 end
迭代器位于最后一个元素 (http://en.cppreference.com/w/cpp/iterator/end) 之后,即容器内的迭代器是:[begin, end].
我最喜欢,因为它不涉及异常处理(当不需要时)。
但除此之外,还有另一种选择(我喜欢这种选择,因为它很短并且保持较低的 map
操作数):
bool retval = false;
try{
const Asdf &a=map1.at(index1);
const Bsdf &b=map2.at(index2);
retval = true;
std::cout<<a[b[42]];
}catch(std::out_of_range&){
return reval;
}
// more code?
return reval;
一个非常规的解决方案是利用 lambda 的捕获将引用变量的范围扩展到块的范围之外。由于引用引用的对象在范围块之外有效,因此只要地图对象保留在范围内,捕获的引用在以后使用时就不会过时。
举个例子
#include <functional>
#include <vector>
int main()
{
std::vector<std::vector< int > > map1 = { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } };
std::function<int()> fn;
try{
const auto &a = map1.at(1);
const auto &b = map1.at(2);
fn = [&]() {return a[b[1]]; };
}
catch (std::out_of_range&){
return false;
}
fn(); // Any exception thrown here would be caught separately from the above try catch block
}
考虑这段代码:
try {
const Asdf &a = map1.at(index1);
const Bsdf &b = map2.at(index2);
} catch(std::out_of_range&) {
return false;
}
// <code>
std::cout<<a[b[42]]; // May throw std::out_of_range which should not be caught here.
return true;
<code>
使用 a 和 b。我有两个选择:
- 将
<code>
放入try块 - 在 try 块中获取指针,然后取消引用它们
第一个选项是错误的,因为如果 <code>
抛出 std::out_of_range
函数将 return false,只有在地图查找失败时才会发生这种情况。
第二个选项可能有点难看:
const Asdf *a;
const Bsdf *b;
try {
a = &map1.at(index1); // What?
b = &map2.at(index2);
} catch(std::out_of_range&) {
return false;
}
std::cout << (*a)[(*b)[42]];
return true;
有没有更好的方法? Python 中的 try-except-else 之类的东西会很好,但在 C++ 中不存在。
一种解决方法是确保地图确实包含该项目。它增加了开销,但在我所知道的许多更糟糕的方法中并没有那么糟糕。
try{
map1.at(index1);
map2.at(index2);
}catch(std::out_of_range&){
return false;
}
const Asdf &a=map1.at(index1);
const Bsdf &b=map2.at(index2);
或者如果以更好的方式编写(抱歉,没有性能提升,只有可读性),除非您想牺牲 const
引用。
if(map1.find(index1) == map1.end() || map2.find(index2) == map2.end()) return false;
const Asdf &a=map1.at(index1);
const Bsdf &b=map2.at(index2);
您也可以使用 std::map::const_iterator 而无需 try-catch 块。
std::map::const_iterator a = map1.find(index1);
if(a == map1.end()) return false;
std::map::const_iterator b = map1.find(index2);
if(b == map2.end()) return false;
对只读 a->second
和 b->second
做任何事情。
解决方案 1:
为什么将代码包含在 try catch 中,将其嵌入到自己的 try catch 块中以区分两种情况?
try {
const Asdf &a = map1.at(index1);
const Bsdf &b = map2.at(index2);
try {
// <code>
std::cout<<a[b[42]]; // May throw std::out_of_range which should not be caught here.
} catch (std::out_of_range&) {}
} catch(std::out_of_range&) {
return false;
}
return true;
但是当然,在这种方法中,您不能将 out_of_range
转发到函数外部,而 out_of_range
会在 <code>
.
解决方案 2:
另一种方法是使用 map::count()
简单地检查键的存在,而不需要异常捕获:
if (map1.count(index1)==0 || map2.count(index2)==0) {
return false;
}
const Asdf &a = map1.at(index1);
const Bsdf &b = map2.at(index2);
// <code>
std::cout<<a[b[42]];
return true;
不需要做任何异常处理。 std::map::find
,给定一个键,会给你一个迭代器。如果地图中不存在该元素,则 find
将 return end
迭代器(即 map.end()
)。
取消引用迭代器时,您将收到一对值。第一个是键,第二个是对象。
auto aIt = map1.find(index1);
auto bIt = map2.find(index2);
if(aIt == map1.end() || bIt == map2.end())
{
return false;
}
const Asdf &a = aIt->second;
const Bsdf &b = bIt->second;
std::cout << a[b[42]];
return true;
请注意,C++ 中的迭代器是这样定义的,即 begin
迭代器位于开始位置,而 end
迭代器位于最后一个元素 (http://en.cppreference.com/w/cpp/iterator/end) 之后,即容器内的迭代器是:[begin, end].
我最喜欢
但除此之外,还有另一种选择(我喜欢这种选择,因为它很短并且保持较低的 map
操作数):
bool retval = false;
try{
const Asdf &a=map1.at(index1);
const Bsdf &b=map2.at(index2);
retval = true;
std::cout<<a[b[42]];
}catch(std::out_of_range&){
return reval;
}
// more code?
return reval;
一个非常规的解决方案是利用 lambda 的捕获将引用变量的范围扩展到块的范围之外。由于引用引用的对象在范围块之外有效,因此只要地图对象保留在范围内,捕获的引用在以后使用时就不会过时。
举个例子
#include <functional>
#include <vector>
int main()
{
std::vector<std::vector< int > > map1 = { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } };
std::function<int()> fn;
try{
const auto &a = map1.at(1);
const auto &b = map1.at(2);
fn = [&]() {return a[b[1]]; };
}
catch (std::out_of_range&){
return false;
}
fn(); // Any exception thrown here would be caught separately from the above try catch block
}