Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ scope of variables inside try

Consider this code:

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> uses a and b. I have two options:

  • Put <code> in the try block
  • Take pointers in the try block, dereference them afterwards

The first option is wrong because if <code> throws std::out_of_range the function will return false, which should only happen if the map lookup fails.

The second option can be a bit ugly:

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;

Is there a better way? Something like try-except-else in Python would be nice, but that doesn't exist in C++.

like image 307
Hristo Venev Avatar asked Apr 19 '15 12:04

Hristo Venev


People also ask

How do you access variables in try block?

Variables in try block So, if you declare a variable in try block, (for that matter in any block) it will be local to that particular block, the life time of the variable expires after the execution of the block. Therefore, you cannot access any variable declared in a block, outside it.

Is try catch scoped?

Variables declared within the try/catch block are not in scope in the containing block, for the same reason that all other variable declarations are local to the scope in which they occur: That's how the specification defines it. :-) (More below, including a reply to your comment.)

Are variables in a try block local?

Variables declared inside a try or catch block are local to the scope of the block.

What is the scope of the variables in C?

In simple terms, scope of a variable is its lifetime in the program. This means that the scope of a variable is the block of code in the entire program where the variable is declared, used, and can be modified.


2 Answers

It's not necessary to do any exception handling. std::map::find, given a key, will give you an iterator. If the element doesn't exist within the map, then find will return the end iterator (i.e. map.end()).

When de-referencing the iterator, you will receive a pair of values. The first being the key and the second being the object.

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;

Note that iterators in C++ are defined such that the begin iterator is at the start and the end iterator is past the last element (http://en.cppreference.com/w/cpp/iterator/end), i.e. the range for iterators within a container is: [begin, end).

like image 97
miguel.martin Avatar answered Sep 20 '22 12:09

miguel.martin


Solution 1:

Why include the code in the try catch, embedding it in its own try catch block to make the difference between the two cases?

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;

But of course in this approach you can't forward to the outside of your function an out_of_range that would occur in your <code>.

Solution 2:

The other alternative is to simply check existence of the keys using map::count() without the need for exception catching:

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;
like image 27
Christophe Avatar answered Sep 17 '22 12:09

Christophe