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

The name of the pictureThe name of the pictureThe name of the pictureClash 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;








42















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.










share|improve this question



















  • 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












  • 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

















42















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.










share|improve this question



















  • 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












  • 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













42












42








42








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.










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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






  • 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





    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






  • 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












2 Answers
2






active

oldest

votes


















42














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






share|improve this answer
































    -11














    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;






    share|improve this answer


















    • 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











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



    );













    draft saved

    draft discarded


















    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









    42














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






    share|improve this answer





























      42














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






      share|improve this answer



























        42












        42








        42







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






        share|improve this answer















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







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Mar 12 at 9:58

























        answered Mar 12 at 9:51









        StoryTellerStoryTeller

        105k13221285




        105k13221285























            -11














            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;






            share|improve this answer


















            • 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














            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;






            share|improve this answer


















            • 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








            -11







            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;






            share|improve this answer













            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;







            share|improve this answer












            share|improve this answer



            share|improve this answer










            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












            • 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

















            draft saved

            draft discarded
















































            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.




            draft saved


            draft discarded














            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





















































            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






            Popular posts from this blog

            How to check contact read email or not when send email to Individual?

            Bahrain

            Postfix configuration issue with fips on centos 7; mailgun relay