What's the lifetime of temporary objects in a range-for?












3















Consider this class:



class Foo
{
public:

~ Foo ()
{
std::cout << "~Foon";
}

typedef std::vector<std::string> Words;

const Words & words ()
{
return m_words;
}

private:

Words m_words = {"foo", "bar", "baz"};
};


Section 12.2 of the C++ standard specifies lifetimes of temporary objects. I thought this would be okay:



for (auto w : Foo () .words ())
std::cout << w << "n";


But it wasn't



~Foo
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
[1] 10290 abort (core dumped) ./a.out


The standard is confusing me. Why is ~Foo being called before the loop runs?










share|improve this question





























    3















    Consider this class:



    class Foo
    {
    public:

    ~ Foo ()
    {
    std::cout << "~Foon";
    }

    typedef std::vector<std::string> Words;

    const Words & words ()
    {
    return m_words;
    }

    private:

    Words m_words = {"foo", "bar", "baz"};
    };


    Section 12.2 of the C++ standard specifies lifetimes of temporary objects. I thought this would be okay:



    for (auto w : Foo () .words ())
    std::cout << w << "n";


    But it wasn't



    ~Foo
    terminate called after throwing an instance of 'std::logic_error'
    what(): basic_string::_M_construct null not valid
    [1] 10290 abort (core dumped) ./a.out


    The standard is confusing me. Why is ~Foo being called before the loop runs?










    share|improve this question



























      3












      3








      3








      Consider this class:



      class Foo
      {
      public:

      ~ Foo ()
      {
      std::cout << "~Foon";
      }

      typedef std::vector<std::string> Words;

      const Words & words ()
      {
      return m_words;
      }

      private:

      Words m_words = {"foo", "bar", "baz"};
      };


      Section 12.2 of the C++ standard specifies lifetimes of temporary objects. I thought this would be okay:



      for (auto w : Foo () .words ())
      std::cout << w << "n";


      But it wasn't



      ~Foo
      terminate called after throwing an instance of 'std::logic_error'
      what(): basic_string::_M_construct null not valid
      [1] 10290 abort (core dumped) ./a.out


      The standard is confusing me. Why is ~Foo being called before the loop runs?










      share|improve this question
















      Consider this class:



      class Foo
      {
      public:

      ~ Foo ()
      {
      std::cout << "~Foon";
      }

      typedef std::vector<std::string> Words;

      const Words & words ()
      {
      return m_words;
      }

      private:

      Words m_words = {"foo", "bar", "baz"};
      };


      Section 12.2 of the C++ standard specifies lifetimes of temporary objects. I thought this would be okay:



      for (auto w : Foo () .words ())
      std::cout << w << "n";


      But it wasn't



      ~Foo
      terminate called after throwing an instance of 'std::logic_error'
      what(): basic_string::_M_construct null not valid
      [1] 10290 abort (core dumped) ./a.out


      The standard is confusing me. Why is ~Foo being called before the loop runs?







      c++ c++11 for-loop temporary-objects






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 2 at 7:33









      xeros

      1068




      1068










      asked Jan 1 at 19:28









      spraffspraff

      18k1486167




      18k1486167
























          2 Answers
          2






          active

          oldest

          votes


















          4














          The current standard says in The range-based for statement [stmt.ranged] that




          The range-based for statement
          for ( init-statementopt for-range-declaration : for-range-initializer ) statement

          is equivalent to



          {
          init-statementopt
          auto &&__range = for-range-initializer ;
          auto __begin = begin-expr ;
          auto __end = end-expr ;
          for ( ; __begin != __end; ++__begin ) {
          for-range-declaration = *__begin;
          statement
          }
          }



          This means that your Foo().words() is only used in the assignment auto &&__range = Foo().words(); and that the temporary object not lives until the code reaches the for loop.



          Please note that I copied from the latest C++20 draft. In C++11 the code is a bit different, but the relevant part is the same.






          share|improve this answer

































            1














            I think that the answer is to be found in the way the range-for is defined and to what __range is bound to.




            [class.temporary]/6 - There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression.




            • The third context is when a reference is bound to a temporary object. The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference ...




            If you change the for-loop expression to bind directly to the subobject m_words(assuming that it were public), then the lifetime of Foo() will be extended and the following will work



            for (auto w : Foo ().m_words)
            std::cout << w << "n";





            share|improve this answer

























              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%2f53998307%2fwhats-the-lifetime-of-temporary-objects-in-a-range-for%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









              4














              The current standard says in The range-based for statement [stmt.ranged] that




              The range-based for statement
              for ( init-statementopt for-range-declaration : for-range-initializer ) statement

              is equivalent to



              {
              init-statementopt
              auto &&__range = for-range-initializer ;
              auto __begin = begin-expr ;
              auto __end = end-expr ;
              for ( ; __begin != __end; ++__begin ) {
              for-range-declaration = *__begin;
              statement
              }
              }



              This means that your Foo().words() is only used in the assignment auto &&__range = Foo().words(); and that the temporary object not lives until the code reaches the for loop.



              Please note that I copied from the latest C++20 draft. In C++11 the code is a bit different, but the relevant part is the same.






              share|improve this answer






























                4














                The current standard says in The range-based for statement [stmt.ranged] that




                The range-based for statement
                for ( init-statementopt for-range-declaration : for-range-initializer ) statement

                is equivalent to



                {
                init-statementopt
                auto &&__range = for-range-initializer ;
                auto __begin = begin-expr ;
                auto __end = end-expr ;
                for ( ; __begin != __end; ++__begin ) {
                for-range-declaration = *__begin;
                statement
                }
                }



                This means that your Foo().words() is only used in the assignment auto &&__range = Foo().words(); and that the temporary object not lives until the code reaches the for loop.



                Please note that I copied from the latest C++20 draft. In C++11 the code is a bit different, but the relevant part is the same.






                share|improve this answer




























                  4












                  4








                  4







                  The current standard says in The range-based for statement [stmt.ranged] that




                  The range-based for statement
                  for ( init-statementopt for-range-declaration : for-range-initializer ) statement

                  is equivalent to



                  {
                  init-statementopt
                  auto &&__range = for-range-initializer ;
                  auto __begin = begin-expr ;
                  auto __end = end-expr ;
                  for ( ; __begin != __end; ++__begin ) {
                  for-range-declaration = *__begin;
                  statement
                  }
                  }



                  This means that your Foo().words() is only used in the assignment auto &&__range = Foo().words(); and that the temporary object not lives until the code reaches the for loop.



                  Please note that I copied from the latest C++20 draft. In C++11 the code is a bit different, but the relevant part is the same.






                  share|improve this answer















                  The current standard says in The range-based for statement [stmt.ranged] that




                  The range-based for statement
                  for ( init-statementopt for-range-declaration : for-range-initializer ) statement

                  is equivalent to



                  {
                  init-statementopt
                  auto &&__range = for-range-initializer ;
                  auto __begin = begin-expr ;
                  auto __end = end-expr ;
                  for ( ; __begin != __end; ++__begin ) {
                  for-range-declaration = *__begin;
                  statement
                  }
                  }



                  This means that your Foo().words() is only used in the assignment auto &&__range = Foo().words(); and that the temporary object not lives until the code reaches the for loop.



                  Please note that I copied from the latest C++20 draft. In C++11 the code is a bit different, but the relevant part is the same.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Jan 1 at 19:45

























                  answered Jan 1 at 19:39









                  Werner HenzeWerner Henze

                  10.7k72854




                  10.7k72854

























                      1














                      I think that the answer is to be found in the way the range-for is defined and to what __range is bound to.




                      [class.temporary]/6 - There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression.




                      • The third context is when a reference is bound to a temporary object. The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference ...




                      If you change the for-loop expression to bind directly to the subobject m_words(assuming that it were public), then the lifetime of Foo() will be extended and the following will work



                      for (auto w : Foo ().m_words)
                      std::cout << w << "n";





                      share|improve this answer






























                        1














                        I think that the answer is to be found in the way the range-for is defined and to what __range is bound to.




                        [class.temporary]/6 - There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression.




                        • The third context is when a reference is bound to a temporary object. The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference ...




                        If you change the for-loop expression to bind directly to the subobject m_words(assuming that it were public), then the lifetime of Foo() will be extended and the following will work



                        for (auto w : Foo ().m_words)
                        std::cout << w << "n";





                        share|improve this answer




























                          1












                          1








                          1







                          I think that the answer is to be found in the way the range-for is defined and to what __range is bound to.




                          [class.temporary]/6 - There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression.




                          • The third context is when a reference is bound to a temporary object. The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference ...




                          If you change the for-loop expression to bind directly to the subobject m_words(assuming that it were public), then the lifetime of Foo() will be extended and the following will work



                          for (auto w : Foo ().m_words)
                          std::cout << w << "n";





                          share|improve this answer















                          I think that the answer is to be found in the way the range-for is defined and to what __range is bound to.




                          [class.temporary]/6 - There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression.




                          • The third context is when a reference is bound to a temporary object. The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference ...




                          If you change the for-loop expression to bind directly to the subobject m_words(assuming that it were public), then the lifetime of Foo() will be extended and the following will work



                          for (auto w : Foo ().m_words)
                          std::cout << w << "n";






                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Jan 2 at 1:31

























                          answered Jan 1 at 19:45









                          JansJans

                          9,02422635




                          9,02422635






























                              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%2f53998307%2fwhats-the-lifetime-of-temporary-objects-in-a-range-for%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

                              Monofisismo

                              Angular Downloading a file using contenturl with Basic Authentication

                              Olmecas