Try Catch Block Affecting a Variable in an Enclosing Scope












32















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




















  • 4





    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
    12 hours ago













  • I can reproduce it with "gcc (GCC) 7.4.0", cygwin version

    – Gojita
    11 hours ago






  • 1





    It seems issue relating to flushing your output .. I will give it a try on GCC and post an answer for you

    – Marzouk
    11 hours ago











  • @lubgr thanks it worked.

    – Aditya Ishan
    11 hours ago











  • I can also reproduce on GCC 8.3, MSYS2 version.

    – HolyBlackCat
    5 hours ago
















32















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




















  • 4





    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
    12 hours ago













  • I can reproduce it with "gcc (GCC) 7.4.0", cygwin version

    – Gojita
    11 hours ago






  • 1





    It seems issue relating to flushing your output .. I will give it a try on GCC and post an answer for you

    – Marzouk
    11 hours ago











  • @lubgr thanks it worked.

    – Aditya Ishan
    11 hours ago











  • I can also reproduce on GCC 8.3, MSYS2 version.

    – HolyBlackCat
    5 hours ago














32












32








32








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 10 hours ago









StoryTeller

101k12213277




101k12213277










asked 12 hours ago









Aditya IshanAditya Ishan

181110




181110








  • 4





    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
    12 hours ago













  • I can reproduce it with "gcc (GCC) 7.4.0", cygwin version

    – Gojita
    11 hours ago






  • 1





    It seems issue relating to flushing your output .. I will give it a try on GCC and post an answer for you

    – Marzouk
    11 hours ago











  • @lubgr thanks it worked.

    – Aditya Ishan
    11 hours ago











  • I can also reproduce on GCC 8.3, MSYS2 version.

    – HolyBlackCat
    5 hours ago














  • 4





    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
    12 hours ago













  • I can reproduce it with "gcc (GCC) 7.4.0", cygwin version

    – Gojita
    11 hours ago






  • 1





    It seems issue relating to flushing your output .. I will give it a try on GCC and post an answer for you

    – Marzouk
    11 hours ago











  • @lubgr thanks it worked.

    – Aditya Ishan
    11 hours ago











  • I can also reproduce on GCC 8.3, MSYS2 version.

    – HolyBlackCat
    5 hours ago








4




4





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
12 hours ago







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
12 hours ago















I can reproduce it with "gcc (GCC) 7.4.0", cygwin version

– Gojita
11 hours ago





I can reproduce it with "gcc (GCC) 7.4.0", cygwin version

– Gojita
11 hours ago




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
11 hours ago





It seems issue relating to flushing your output .. I will give it a try on GCC and post an answer for you

– Marzouk
11 hours ago













@lubgr thanks it worked.

– Aditya Ishan
11 hours ago





@lubgr thanks it worked.

– Aditya Ishan
11 hours ago













I can also reproduce on GCC 8.3, MSYS2 version.

– HolyBlackCat
5 hours ago





I can also reproduce on GCC 8.3, MSYS2 version.

– HolyBlackCat
5 hours ago












2 Answers
2






active

oldest

votes


















32














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

































    -7














    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



















    • 9





      An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.

      – Christian Severin
      8 hours ago











    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%2ftry-catch-block-affecting-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









    32














    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






























      32














      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




























        32












        32








        32







        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 11 hours ago

























        answered 11 hours ago









        StoryTellerStoryTeller

        101k12213277




        101k12213277

























            -7














            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



















            • 9





              An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.

              – Christian Severin
              8 hours ago
















            -7














            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



















            • 9





              An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.

              – Christian Severin
              8 hours ago














            -7












            -7








            -7







            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 11 hours ago









            ManojManoj

            431318




            431318








            • 9





              An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.

              – Christian Severin
              8 hours ago














            • 9





              An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.

              – Christian Severin
              8 hours ago








            9




            9





            An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.

            – Christian Severin
            8 hours ago





            An hour before you wrote your answer, this solution was mentioned both in a comment and in the answer by @StoryTeller.

            – Christian Severin
            8 hours ago


















            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%2ftry-catch-block-affecting-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

            Callistus I

            Tabula Rosettana

            How to label and detect the document text images