Why does the Try-Catch block affect a variable in an enclosing scope?
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
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.
c++ try-catch
|
show 3 more comments
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.
c++ try-catch
5
Seems to work fine and as expected withclang 7
. Reproducible withgcc 8
, declaringtemp
asconst std::string temp("exception");
seems to fix this.
– lubgr
Mar 12 at 9:43
I can reproduce it with "gcc (GCC) 7.4.0", cygwin version
– Gojita
Mar 12 at 9:44
1
It seems issue relating to flushing your output .. I will give it a try on GCC and post an answer for you
– Marzouk
Mar 12 at 9:47
@lubgr thanks it worked.
– Aditya Ishan
Mar 12 at 9:50
I can also reproduce on GCC 8.3, MSYS2 version.
– HolyBlackCat
Mar 12 at 16:36
|
show 3 more comments
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.
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.
c++ try-catch
c++ try-catch
edited Apr 3 at 4:59
Ajay Kumar Ganesh
1,57111629
1,57111629
asked Mar 12 at 9:37
Aditya IshanAditya Ishan
362314
362314
5
Seems to work fine and as expected withclang 7
. Reproducible withgcc 8
, declaringtemp
asconst std::string temp("exception");
seems to fix this.
– lubgr
Mar 12 at 9:43
I can reproduce it with "gcc (GCC) 7.4.0", cygwin version
– Gojita
Mar 12 at 9:44
1
It seems issue relating to flushing your output .. I will give it a try on GCC and post an answer for you
– Marzouk
Mar 12 at 9:47
@lubgr thanks it worked.
– Aditya Ishan
Mar 12 at 9:50
I can also reproduce on GCC 8.3, MSYS2 version.
– HolyBlackCat
Mar 12 at 16:36
|
show 3 more comments
5
Seems to work fine and as expected withclang 7
. Reproducible withgcc 8
, declaringtemp
asconst std::string temp("exception");
seems to fix this.
– lubgr
Mar 12 at 9:43
I can reproduce it with "gcc (GCC) 7.4.0", cygwin version
– Gojita
Mar 12 at 9:44
1
It seems issue relating to flushing your output .. I will give it a try on GCC and post an answer for you
– Marzouk
Mar 12 at 9:47
@lubgr thanks it worked.
– Aditya Ishan
Mar 12 at 9:50
I can also reproduce on GCC 8.3, MSYS2 version.
– HolyBlackCat
Mar 12 at 16:36
5
5
Seems to work fine and as expected with
clang 7
. Reproducible with gcc 8
, declaring temp
as const std::string temp("exception");
seems to fix this.– lubgr
Mar 12 at 9:43
Seems to work fine and as expected with
clang 7
. Reproducible with gcc 8
, declaring temp
as const std::string temp("exception");
seems to fix this.– lubgr
Mar 12 at 9:43
I can reproduce it with "gcc (GCC) 7.4.0", cygwin version
– Gojita
Mar 12 at 9:44
I can reproduce it with "gcc (GCC) 7.4.0", cygwin version
– Gojita
Mar 12 at 9:44
1
1
It seems issue relating to flushing your output .. I will give it a try on GCC and post an answer for you
– Marzouk
Mar 12 at 9:47
It seems issue relating to flushing your output .. I will give it a try on GCC and post an answer for you
– Marzouk
Mar 12 at 9:47
@lubgr thanks it worked.
– Aditya Ishan
Mar 12 at 9:50
@lubgr thanks it worked.
– Aditya Ishan
Mar 12 at 9:50
I can also reproduce on GCC 8.3, MSYS2 version.
– HolyBlackCat
Mar 12 at 16:36
I can also reproduce on GCC 8.3, MSYS2 version.
– HolyBlackCat
Mar 12 at 16:36
|
show 3 more comments
2 Answers
2
active
oldest
votes
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).
add a comment |
I am not sure if it is a bug or not as mentioned in another answer but somehow catch block is changing / omitting the content of temp after handling the exception once. Below code resolves this issue. Make the temp
a const
to solve this.
#include <iostream>
int main()
const 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::cerr << temp << "n";
return 0;
11
An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.
– Christian Severin
Mar 12 at 13:06
3
Believe it or not, I didn't really see those comments and had started playing with this code and as soon as it worked I posted my answer. Taking it as a lesson to read all the comments before posting my answers. Thanks for the down votes.
– Manoj
Mar 13 at 7:57
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55118232%2fwhy-does-the-try-catch-block-affect-a-variable-in-an-enclosing-scope%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
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).
add a comment |
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).
add a comment |
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).
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).
edited Mar 12 at 9:58
answered Mar 12 at 9:51
StoryTellerStoryTeller
105k13221285
105k13221285
add a comment |
add a comment |
I am not sure if it is a bug or not as mentioned in another answer but somehow catch block is changing / omitting the content of temp after handling the exception once. Below code resolves this issue. Make the temp
a const
to solve this.
#include <iostream>
int main()
const 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::cerr << temp << "n";
return 0;
11
An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.
– Christian Severin
Mar 12 at 13:06
3
Believe it or not, I didn't really see those comments and had started playing with this code and as soon as it worked I posted my answer. Taking it as a lesson to read all the comments before posting my answers. Thanks for the down votes.
– Manoj
Mar 13 at 7:57
add a comment |
I am not sure if it is a bug or not as mentioned in another answer but somehow catch block is changing / omitting the content of temp after handling the exception once. Below code resolves this issue. Make the temp
a const
to solve this.
#include <iostream>
int main()
const 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::cerr << temp << "n";
return 0;
11
An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.
– Christian Severin
Mar 12 at 13:06
3
Believe it or not, I didn't really see those comments and had started playing with this code and as soon as it worked I posted my answer. Taking it as a lesson to read all the comments before posting my answers. Thanks for the down votes.
– Manoj
Mar 13 at 7:57
add a comment |
I am not sure if it is a bug or not as mentioned in another answer but somehow catch block is changing / omitting the content of temp after handling the exception once. Below code resolves this issue. Make the temp
a const
to solve this.
#include <iostream>
int main()
const 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::cerr << temp << "n";
return 0;
I am not sure if it is a bug or not as mentioned in another answer but somehow catch block is changing / omitting the content of temp after handling the exception once. Below code resolves this issue. Make the temp
a const
to solve this.
#include <iostream>
int main()
const 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::cerr << temp << "n";
return 0;
answered Mar 12 at 10:08
ManojManoj
433318
433318
11
An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.
– Christian Severin
Mar 12 at 13:06
3
Believe it or not, I didn't really see those comments and had started playing with this code and as soon as it worked I posted my answer. Taking it as a lesson to read all the comments before posting my answers. Thanks for the down votes.
– Manoj
Mar 13 at 7:57
add a comment |
11
An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.
– Christian Severin
Mar 12 at 13:06
3
Believe it or not, I didn't really see those comments and had started playing with this code and as soon as it worked I posted my answer. Taking it as a lesson to read all the comments before posting my answers. Thanks for the down votes.
– Manoj
Mar 13 at 7:57
11
11
An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.
– Christian Severin
Mar 12 at 13:06
An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.
– Christian Severin
Mar 12 at 13:06
3
3
Believe it or not, I didn't really see those comments and had started playing with this code and as soon as it worked I posted my answer. Taking it as a lesson to read all the comments before posting my answers. Thanks for the down votes.
– Manoj
Mar 13 at 7:57
Believe it or not, I didn't really see those comments and had started playing with this code and as soon as it worked I posted my answer. Taking it as a lesson to read all the comments before posting my answers. Thanks for the down votes.
– Manoj
Mar 13 at 7:57
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55118232%2fwhy-does-the-try-catch-block-affect-a-variable-in-an-enclosing-scope%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
5
Seems to work fine and as expected with
clang 7
. Reproducible withgcc 8
, declaringtemp
asconst std::string temp("exception");
seems to fix this.– lubgr
Mar 12 at 9:43
I can reproduce it with "gcc (GCC) 7.4.0", cygwin version
– Gojita
Mar 12 at 9:44
1
It seems issue relating to flushing your output .. I will give it a try on GCC and post an answer for you
– Marzouk
Mar 12 at 9:47
@lubgr thanks it worked.
– Aditya Ishan
Mar 12 at 9:50
I can also reproduce on GCC 8.3, MSYS2 version.
– HolyBlackCat
Mar 12 at 16:36