Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the Try-Catch block affect a variable in an enclosing scope?

Tags:

c++

try-catch

Why does the outer temp become empty after catching first exception?

#include <iostream> int main() {     std::string temp("exception");     int value;     while(std::cin>> value && value != 0)     {          try{               if(value > 9) throw temp;               else std::cout << value << "\n";             }          catch(std::string temp)          {               std::cout << temp << "\n";          }     }      return 0; } 

Input:

1 2 11 13 

Output:

1 2 exception // Printing Empty string 

Expected Output:

1 2 exception exception 

I compile my code with g++ 7.3.0.

like image 982
Aditya Ishan Avatar asked Mar 12 '19 09:03

Aditya Ishan


People also ask

Why variables defined in try Cannot be used in catch or finally in Java?

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.

Do try catch blocks have scope?

Try-Catch and Variable Scope -it is not available to the scope outside. We would have the same problem if we tried to return the price inside of the catch block. Here's a key point: Variables declared inside a try or catch block are local to the scope of the block.

Can we declare variable in catch block?

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.)


1 Answers

This appears to be a bug in GCC's implementation of copy elision. The C++ standard says the following:

[class.copy.elision] (emphasis mine)

This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

  • in a throw-expression, when the operand is the name of a non-volatile automatic object (other than a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one), the copy/move operation from the operand to the exception object can be omitted by constructing the automatic object directly into the exception object

In the following copy-initialization contexts, a move operation might be used instead of a copy operation:

  • if the operand of a throw-expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one),

This is a family of optimizations that allows the copy initialization of an exception object to be either avoided or done as efficiently as possible. Now, a common implementation of std::string move construction is to leave the source string empty. This appears to be exactly what happens to your code. The temp in the outer scope is moved from (and left empty).

But that is not the intended behavior. The scope of the temp you throw exceeds (by far) the try block it's thrown in. So GCC has no business applying copy elision to it.

A possible workaround is to place the declaration of temp inside the while loop. This initialized a new std::string object every iteration, so even if GCC moves from it, it won't be noticeable.

Another workaround was mentioned in the comments and is to make the outer temp a const object. This will force a copy (since a move operation requires a non-const source object).

like image 165
StoryTeller - Unslander Monica Avatar answered Oct 09 '22 10:10

StoryTeller - Unslander Monica