Returning shared pointer reference breaks outside of class methods










0















I have a tree in C++ and a method in the Tree that returns a shared_ptr reference to a new leaf whenever that leaf is added to the tree. When I use this inside other methods of the Tree class it works fine, but when I try to call it from main, it crashes, despite the code seemingly doing the same thing.



Here's the Node and Tree classes:



#include <iostream>
#include <vector>
#include <memory>

class Node

public:
int value;
std::vector<std::shared_ptr<Node> > children;
Node(int value): valuevalue
;

class Tree

public:
std::shared_ptr<Node> root;
Tree(): root nullptr

std::shared_ptr<Node> CreateLeaf(int value)

return std::make_shared<Node>(value);


std::shared_ptr<Node>& AddLeaf(int value, std::shared_ptr<Node>& ptr)

if(ptr == nullptr)

ptr = std::move(CreateLeaf(value));
return ptr;

else

std::shared_ptr<Node> newLeaf = CreateLeaf(value);
ptr->children.push_back(std::move(newLeaf));
return ptr->children.back();



void otherMethod()

AddLeaf(1, root);
std::shared_ptr<Node>& temporary = AddLeaf(2, root);
std::cout << "temporary->value: " << temporary->value << std::endl;


;


If the main function is:



int main()

Tree t;
t.otherMethod();



Then the program runs correctly.



However, if the main function is:



int main()

Tree t;
t.AddLeaf(1, t.root);
std::shared_ptr<Node>& b = t.AddLeaf(2, t.root);
std::cout << "b->value = " << b->value << std::endl;




the program crashes, despite it doing pretty much the same thing. It seems like AddLeaf is just storing the nullptr in b, despite it being a reference to a persistent object, t.root->children[0]. Why is it doing that?










share|improve this question


























    0















    I have a tree in C++ and a method in the Tree that returns a shared_ptr reference to a new leaf whenever that leaf is added to the tree. When I use this inside other methods of the Tree class it works fine, but when I try to call it from main, it crashes, despite the code seemingly doing the same thing.



    Here's the Node and Tree classes:



    #include <iostream>
    #include <vector>
    #include <memory>

    class Node

    public:
    int value;
    std::vector<std::shared_ptr<Node> > children;
    Node(int value): valuevalue
    ;

    class Tree

    public:
    std::shared_ptr<Node> root;
    Tree(): root nullptr

    std::shared_ptr<Node> CreateLeaf(int value)

    return std::make_shared<Node>(value);


    std::shared_ptr<Node>& AddLeaf(int value, std::shared_ptr<Node>& ptr)

    if(ptr == nullptr)

    ptr = std::move(CreateLeaf(value));
    return ptr;

    else

    std::shared_ptr<Node> newLeaf = CreateLeaf(value);
    ptr->children.push_back(std::move(newLeaf));
    return ptr->children.back();



    void otherMethod()

    AddLeaf(1, root);
    std::shared_ptr<Node>& temporary = AddLeaf(2, root);
    std::cout << "temporary->value: " << temporary->value << std::endl;


    ;


    If the main function is:



    int main()

    Tree t;
    t.otherMethod();



    Then the program runs correctly.



    However, if the main function is:



    int main()

    Tree t;
    t.AddLeaf(1, t.root);
    std::shared_ptr<Node>& b = t.AddLeaf(2, t.root);
    std::cout << "b->value = " << b->value << std::endl;




    the program crashes, despite it doing pretty much the same thing. It seems like AddLeaf is just storing the nullptr in b, despite it being a reference to a persistent object, t.root->children[0]. Why is it doing that?










    share|improve this question
























      0












      0








      0








      I have a tree in C++ and a method in the Tree that returns a shared_ptr reference to a new leaf whenever that leaf is added to the tree. When I use this inside other methods of the Tree class it works fine, but when I try to call it from main, it crashes, despite the code seemingly doing the same thing.



      Here's the Node and Tree classes:



      #include <iostream>
      #include <vector>
      #include <memory>

      class Node

      public:
      int value;
      std::vector<std::shared_ptr<Node> > children;
      Node(int value): valuevalue
      ;

      class Tree

      public:
      std::shared_ptr<Node> root;
      Tree(): root nullptr

      std::shared_ptr<Node> CreateLeaf(int value)

      return std::make_shared<Node>(value);


      std::shared_ptr<Node>& AddLeaf(int value, std::shared_ptr<Node>& ptr)

      if(ptr == nullptr)

      ptr = std::move(CreateLeaf(value));
      return ptr;

      else

      std::shared_ptr<Node> newLeaf = CreateLeaf(value);
      ptr->children.push_back(std::move(newLeaf));
      return ptr->children.back();



      void otherMethod()

      AddLeaf(1, root);
      std::shared_ptr<Node>& temporary = AddLeaf(2, root);
      std::cout << "temporary->value: " << temporary->value << std::endl;


      ;


      If the main function is:



      int main()

      Tree t;
      t.otherMethod();



      Then the program runs correctly.



      However, if the main function is:



      int main()

      Tree t;
      t.AddLeaf(1, t.root);
      std::shared_ptr<Node>& b = t.AddLeaf(2, t.root);
      std::cout << "b->value = " << b->value << std::endl;




      the program crashes, despite it doing pretty much the same thing. It seems like AddLeaf is just storing the nullptr in b, despite it being a reference to a persistent object, t.root->children[0]. Why is it doing that?










      share|improve this question














      I have a tree in C++ and a method in the Tree that returns a shared_ptr reference to a new leaf whenever that leaf is added to the tree. When I use this inside other methods of the Tree class it works fine, but when I try to call it from main, it crashes, despite the code seemingly doing the same thing.



      Here's the Node and Tree classes:



      #include <iostream>
      #include <vector>
      #include <memory>

      class Node

      public:
      int value;
      std::vector<std::shared_ptr<Node> > children;
      Node(int value): valuevalue
      ;

      class Tree

      public:
      std::shared_ptr<Node> root;
      Tree(): root nullptr

      std::shared_ptr<Node> CreateLeaf(int value)

      return std::make_shared<Node>(value);


      std::shared_ptr<Node>& AddLeaf(int value, std::shared_ptr<Node>& ptr)

      if(ptr == nullptr)

      ptr = std::move(CreateLeaf(value));
      return ptr;

      else

      std::shared_ptr<Node> newLeaf = CreateLeaf(value);
      ptr->children.push_back(std::move(newLeaf));
      return ptr->children.back();



      void otherMethod()

      AddLeaf(1, root);
      std::shared_ptr<Node>& temporary = AddLeaf(2, root);
      std::cout << "temporary->value: " << temporary->value << std::endl;


      ;


      If the main function is:



      int main()

      Tree t;
      t.otherMethod();



      Then the program runs correctly.



      However, if the main function is:



      int main()

      Tree t;
      t.AddLeaf(1, t.root);
      std::shared_ptr<Node>& b = t.AddLeaf(2, t.root);
      std::cout << "b->value = " << b->value << std::endl;




      the program crashes, despite it doing pretty much the same thing. It seems like AddLeaf is just storing the nullptr in b, despite it being a reference to a persistent object, t.root->children[0]. Why is it doing that?







      c++ tree shared-ptr






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 15 '18 at 13:21









      user2520385user2520385

      841616




      841616






















          1 Answer
          1






          active

          oldest

          votes


















          1














          Having references to elements in a vector, or any self-resizing container, is dangerous. I've dealt with this when I created my first game in C++.



          Essentially what happens is:



          Your vector resizes when adding a new shared_ptr, which may cause an operation to allocate more memory. During that procedure the currently existing vector is destructed and allocated on possibly a different location in memory.
          Meaning that all currently existing pointers or references to elements in the vector become invalidated and may crash your program at some point.



          Passing out references to shared_ptr's in a vector basically promotes undefined behavior. A smarter move would be to just return a new shared_ptr and have the reference counter just increment.
          That way, when the vector resizes, no reference in your program gets invalidated.



          Removing the reference should help:



          std::shared_ptr<Node> AddLeaf(int value, std::shared_ptr<Node>& ptr)

          if(ptr == nullptr)

          ptr = std::move(CreateLeaf(value));
          return ptr;

          else

          std::shared_ptr<Node> newLeaf = CreateLeaf(value);
          ptr->children.push_back(std::move(newLeaf));
          return ptr->children.back();




          Anyway, as I see you're creating a tree, perhaps you would like to take a look at code I've written in an (abandoned) project: https://github.com/wvanbreukelen/LexMe/blob/feature-tree-node-vector-specialization/LexMe/TreeNode.h
          It's a quite complete implementation for a generic tree with friendliness towards move semantics and iterators.






          share|improve this answer

























          • "Meaning that all currently existing pointers to elements in the vector become invalidated and may crash your program at some point." Where do you see existing pointers to vector elements in this code?

            – melpomene
            Nov 15 '18 at 13:59











          • In this case, it is actually a reference, but semantically it's the about same. I'll edit the answer

            – Julian vD
            Nov 15 '18 at 14:00











          • OK, where are the existing references?

            – melpomene
            Nov 15 '18 at 14:01











          • AddLeaf returns a reference...

            – Julian vD
            Nov 15 '18 at 14:01











          • Yes, go on ...?

            – melpomene
            Nov 15 '18 at 14:03










          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%2f53320441%2freturning-shared-pointer-reference-breaks-outside-of-class-methods%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          Having references to elements in a vector, or any self-resizing container, is dangerous. I've dealt with this when I created my first game in C++.



          Essentially what happens is:



          Your vector resizes when adding a new shared_ptr, which may cause an operation to allocate more memory. During that procedure the currently existing vector is destructed and allocated on possibly a different location in memory.
          Meaning that all currently existing pointers or references to elements in the vector become invalidated and may crash your program at some point.



          Passing out references to shared_ptr's in a vector basically promotes undefined behavior. A smarter move would be to just return a new shared_ptr and have the reference counter just increment.
          That way, when the vector resizes, no reference in your program gets invalidated.



          Removing the reference should help:



          std::shared_ptr<Node> AddLeaf(int value, std::shared_ptr<Node>& ptr)

          if(ptr == nullptr)

          ptr = std::move(CreateLeaf(value));
          return ptr;

          else

          std::shared_ptr<Node> newLeaf = CreateLeaf(value);
          ptr->children.push_back(std::move(newLeaf));
          return ptr->children.back();




          Anyway, as I see you're creating a tree, perhaps you would like to take a look at code I've written in an (abandoned) project: https://github.com/wvanbreukelen/LexMe/blob/feature-tree-node-vector-specialization/LexMe/TreeNode.h
          It's a quite complete implementation for a generic tree with friendliness towards move semantics and iterators.






          share|improve this answer

























          • "Meaning that all currently existing pointers to elements in the vector become invalidated and may crash your program at some point." Where do you see existing pointers to vector elements in this code?

            – melpomene
            Nov 15 '18 at 13:59











          • In this case, it is actually a reference, but semantically it's the about same. I'll edit the answer

            – Julian vD
            Nov 15 '18 at 14:00











          • OK, where are the existing references?

            – melpomene
            Nov 15 '18 at 14:01











          • AddLeaf returns a reference...

            – Julian vD
            Nov 15 '18 at 14:01











          • Yes, go on ...?

            – melpomene
            Nov 15 '18 at 14:03















          1














          Having references to elements in a vector, or any self-resizing container, is dangerous. I've dealt with this when I created my first game in C++.



          Essentially what happens is:



          Your vector resizes when adding a new shared_ptr, which may cause an operation to allocate more memory. During that procedure the currently existing vector is destructed and allocated on possibly a different location in memory.
          Meaning that all currently existing pointers or references to elements in the vector become invalidated and may crash your program at some point.



          Passing out references to shared_ptr's in a vector basically promotes undefined behavior. A smarter move would be to just return a new shared_ptr and have the reference counter just increment.
          That way, when the vector resizes, no reference in your program gets invalidated.



          Removing the reference should help:



          std::shared_ptr<Node> AddLeaf(int value, std::shared_ptr<Node>& ptr)

          if(ptr == nullptr)

          ptr = std::move(CreateLeaf(value));
          return ptr;

          else

          std::shared_ptr<Node> newLeaf = CreateLeaf(value);
          ptr->children.push_back(std::move(newLeaf));
          return ptr->children.back();




          Anyway, as I see you're creating a tree, perhaps you would like to take a look at code I've written in an (abandoned) project: https://github.com/wvanbreukelen/LexMe/blob/feature-tree-node-vector-specialization/LexMe/TreeNode.h
          It's a quite complete implementation for a generic tree with friendliness towards move semantics and iterators.






          share|improve this answer

























          • "Meaning that all currently existing pointers to elements in the vector become invalidated and may crash your program at some point." Where do you see existing pointers to vector elements in this code?

            – melpomene
            Nov 15 '18 at 13:59











          • In this case, it is actually a reference, but semantically it's the about same. I'll edit the answer

            – Julian vD
            Nov 15 '18 at 14:00











          • OK, where are the existing references?

            – melpomene
            Nov 15 '18 at 14:01











          • AddLeaf returns a reference...

            – Julian vD
            Nov 15 '18 at 14:01











          • Yes, go on ...?

            – melpomene
            Nov 15 '18 at 14:03













          1












          1








          1







          Having references to elements in a vector, or any self-resizing container, is dangerous. I've dealt with this when I created my first game in C++.



          Essentially what happens is:



          Your vector resizes when adding a new shared_ptr, which may cause an operation to allocate more memory. During that procedure the currently existing vector is destructed and allocated on possibly a different location in memory.
          Meaning that all currently existing pointers or references to elements in the vector become invalidated and may crash your program at some point.



          Passing out references to shared_ptr's in a vector basically promotes undefined behavior. A smarter move would be to just return a new shared_ptr and have the reference counter just increment.
          That way, when the vector resizes, no reference in your program gets invalidated.



          Removing the reference should help:



          std::shared_ptr<Node> AddLeaf(int value, std::shared_ptr<Node>& ptr)

          if(ptr == nullptr)

          ptr = std::move(CreateLeaf(value));
          return ptr;

          else

          std::shared_ptr<Node> newLeaf = CreateLeaf(value);
          ptr->children.push_back(std::move(newLeaf));
          return ptr->children.back();




          Anyway, as I see you're creating a tree, perhaps you would like to take a look at code I've written in an (abandoned) project: https://github.com/wvanbreukelen/LexMe/blob/feature-tree-node-vector-specialization/LexMe/TreeNode.h
          It's a quite complete implementation for a generic tree with friendliness towards move semantics and iterators.






          share|improve this answer















          Having references to elements in a vector, or any self-resizing container, is dangerous. I've dealt with this when I created my first game in C++.



          Essentially what happens is:



          Your vector resizes when adding a new shared_ptr, which may cause an operation to allocate more memory. During that procedure the currently existing vector is destructed and allocated on possibly a different location in memory.
          Meaning that all currently existing pointers or references to elements in the vector become invalidated and may crash your program at some point.



          Passing out references to shared_ptr's in a vector basically promotes undefined behavior. A smarter move would be to just return a new shared_ptr and have the reference counter just increment.
          That way, when the vector resizes, no reference in your program gets invalidated.



          Removing the reference should help:



          std::shared_ptr<Node> AddLeaf(int value, std::shared_ptr<Node>& ptr)

          if(ptr == nullptr)

          ptr = std::move(CreateLeaf(value));
          return ptr;

          else

          std::shared_ptr<Node> newLeaf = CreateLeaf(value);
          ptr->children.push_back(std::move(newLeaf));
          return ptr->children.back();




          Anyway, as I see you're creating a tree, perhaps you would like to take a look at code I've written in an (abandoned) project: https://github.com/wvanbreukelen/LexMe/blob/feature-tree-node-vector-specialization/LexMe/TreeNode.h
          It's a quite complete implementation for a generic tree with friendliness towards move semantics and iterators.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 15 '18 at 13:59

























          answered Nov 15 '18 at 13:49









          Julian vDJulian vD

          889




          889












          • "Meaning that all currently existing pointers to elements in the vector become invalidated and may crash your program at some point." Where do you see existing pointers to vector elements in this code?

            – melpomene
            Nov 15 '18 at 13:59











          • In this case, it is actually a reference, but semantically it's the about same. I'll edit the answer

            – Julian vD
            Nov 15 '18 at 14:00











          • OK, where are the existing references?

            – melpomene
            Nov 15 '18 at 14:01











          • AddLeaf returns a reference...

            – Julian vD
            Nov 15 '18 at 14:01











          • Yes, go on ...?

            – melpomene
            Nov 15 '18 at 14:03

















          • "Meaning that all currently existing pointers to elements in the vector become invalidated and may crash your program at some point." Where do you see existing pointers to vector elements in this code?

            – melpomene
            Nov 15 '18 at 13:59











          • In this case, it is actually a reference, but semantically it's the about same. I'll edit the answer

            – Julian vD
            Nov 15 '18 at 14:00











          • OK, where are the existing references?

            – melpomene
            Nov 15 '18 at 14:01











          • AddLeaf returns a reference...

            – Julian vD
            Nov 15 '18 at 14:01











          • Yes, go on ...?

            – melpomene
            Nov 15 '18 at 14:03
















          "Meaning that all currently existing pointers to elements in the vector become invalidated and may crash your program at some point." Where do you see existing pointers to vector elements in this code?

          – melpomene
          Nov 15 '18 at 13:59





          "Meaning that all currently existing pointers to elements in the vector become invalidated and may crash your program at some point." Where do you see existing pointers to vector elements in this code?

          – melpomene
          Nov 15 '18 at 13:59













          In this case, it is actually a reference, but semantically it's the about same. I'll edit the answer

          – Julian vD
          Nov 15 '18 at 14:00





          In this case, it is actually a reference, but semantically it's the about same. I'll edit the answer

          – Julian vD
          Nov 15 '18 at 14:00













          OK, where are the existing references?

          – melpomene
          Nov 15 '18 at 14:01





          OK, where are the existing references?

          – melpomene
          Nov 15 '18 at 14:01













          AddLeaf returns a reference...

          – Julian vD
          Nov 15 '18 at 14:01





          AddLeaf returns a reference...

          – Julian vD
          Nov 15 '18 at 14:01













          Yes, go on ...?

          – melpomene
          Nov 15 '18 at 14:03





          Yes, go on ...?

          – melpomene
          Nov 15 '18 at 14:03



















          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%2f53320441%2freturning-shared-pointer-reference-breaks-outside-of-class-methods%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







          這個網誌中的熱門文章

          How to read a connectionString WITH PROVIDER in .NET Core?

          In R, how to develop a multiplot heatmap.2 figure showing key labels successfully

          Museum of Modern and Contemporary Art of Trento and Rovereto