Delayed instantiation in C++












0















I'm trying to create a variable without instantiating the object.



In Python it would look like this:



graph = mymap[c] if c in mymap else Graph() 


So I basically check if I already have that graph otherwise I create it. My understanding is that if I declare the following in C++ it will call the constructor and be wasteful.



Graph g;


So I'm trying to use pointers to avoid this "waste":



    Graph* g;

if (graphs.find(c) == graphs.end()){
g = new Graph();
graphs[c] = *g;
} else {
g = &(graphs[c]);
}

std::cout << g << std::endl;
std::cout << &(graphs[c]) << std::endl;


The problem is that the addresses printed in the end do not match. In fact, my tests show that something weird is happening like a new instance of Graph is being created every time.



What am I doing wrong?










share|improve this question


















  • 3





    Maps already do this. You are allocating an object, then dereferencing it and copying it inside your map, leaking the allocation. Basically not doing what you think it does.

    – Matthieu Brucher
    Nov 20 '18 at 22:36






  • 1





    Could you complete the example, showing the type of c and of graphs (the latter presumably an std::map or std::unordered_map?

    – jwimberley
    Nov 20 '18 at 22:36






  • 1





    There are better solutions, as detailed in 1+ answers, but to clarify: graphs[c] = *g is not doing what you think it is.

    – jwimberley
    Nov 20 '18 at 22:39
















0















I'm trying to create a variable without instantiating the object.



In Python it would look like this:



graph = mymap[c] if c in mymap else Graph() 


So I basically check if I already have that graph otherwise I create it. My understanding is that if I declare the following in C++ it will call the constructor and be wasteful.



Graph g;


So I'm trying to use pointers to avoid this "waste":



    Graph* g;

if (graphs.find(c) == graphs.end()){
g = new Graph();
graphs[c] = *g;
} else {
g = &(graphs[c]);
}

std::cout << g << std::endl;
std::cout << &(graphs[c]) << std::endl;


The problem is that the addresses printed in the end do not match. In fact, my tests show that something weird is happening like a new instance of Graph is being created every time.



What am I doing wrong?










share|improve this question


















  • 3





    Maps already do this. You are allocating an object, then dereferencing it and copying it inside your map, leaking the allocation. Basically not doing what you think it does.

    – Matthieu Brucher
    Nov 20 '18 at 22:36






  • 1





    Could you complete the example, showing the type of c and of graphs (the latter presumably an std::map or std::unordered_map?

    – jwimberley
    Nov 20 '18 at 22:36






  • 1





    There are better solutions, as detailed in 1+ answers, but to clarify: graphs[c] = *g is not doing what you think it is.

    – jwimberley
    Nov 20 '18 at 22:39














0












0








0








I'm trying to create a variable without instantiating the object.



In Python it would look like this:



graph = mymap[c] if c in mymap else Graph() 


So I basically check if I already have that graph otherwise I create it. My understanding is that if I declare the following in C++ it will call the constructor and be wasteful.



Graph g;


So I'm trying to use pointers to avoid this "waste":



    Graph* g;

if (graphs.find(c) == graphs.end()){
g = new Graph();
graphs[c] = *g;
} else {
g = &(graphs[c]);
}

std::cout << g << std::endl;
std::cout << &(graphs[c]) << std::endl;


The problem is that the addresses printed in the end do not match. In fact, my tests show that something weird is happening like a new instance of Graph is being created every time.



What am I doing wrong?










share|improve this question














I'm trying to create a variable without instantiating the object.



In Python it would look like this:



graph = mymap[c] if c in mymap else Graph() 


So I basically check if I already have that graph otherwise I create it. My understanding is that if I declare the following in C++ it will call the constructor and be wasteful.



Graph g;


So I'm trying to use pointers to avoid this "waste":



    Graph* g;

if (graphs.find(c) == graphs.end()){
g = new Graph();
graphs[c] = *g;
} else {
g = &(graphs[c]);
}

std::cout << g << std::endl;
std::cout << &(graphs[c]) << std::endl;


The problem is that the addresses printed in the end do not match. In fact, my tests show that something weird is happening like a new instance of Graph is being created every time.



What am I doing wrong?







c++






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 20 '18 at 22:33









RafaelRafael

345310




345310








  • 3





    Maps already do this. You are allocating an object, then dereferencing it and copying it inside your map, leaking the allocation. Basically not doing what you think it does.

    – Matthieu Brucher
    Nov 20 '18 at 22:36






  • 1





    Could you complete the example, showing the type of c and of graphs (the latter presumably an std::map or std::unordered_map?

    – jwimberley
    Nov 20 '18 at 22:36






  • 1





    There are better solutions, as detailed in 1+ answers, but to clarify: graphs[c] = *g is not doing what you think it is.

    – jwimberley
    Nov 20 '18 at 22:39














  • 3





    Maps already do this. You are allocating an object, then dereferencing it and copying it inside your map, leaking the allocation. Basically not doing what you think it does.

    – Matthieu Brucher
    Nov 20 '18 at 22:36






  • 1





    Could you complete the example, showing the type of c and of graphs (the latter presumably an std::map or std::unordered_map?

    – jwimberley
    Nov 20 '18 at 22:36






  • 1





    There are better solutions, as detailed in 1+ answers, but to clarify: graphs[c] = *g is not doing what you think it is.

    – jwimberley
    Nov 20 '18 at 22:39








3




3





Maps already do this. You are allocating an object, then dereferencing it and copying it inside your map, leaking the allocation. Basically not doing what you think it does.

– Matthieu Brucher
Nov 20 '18 at 22:36





Maps already do this. You are allocating an object, then dereferencing it and copying it inside your map, leaking the allocation. Basically not doing what you think it does.

– Matthieu Brucher
Nov 20 '18 at 22:36




1




1





Could you complete the example, showing the type of c and of graphs (the latter presumably an std::map or std::unordered_map?

– jwimberley
Nov 20 '18 at 22:36





Could you complete the example, showing the type of c and of graphs (the latter presumably an std::map or std::unordered_map?

– jwimberley
Nov 20 '18 at 22:36




1




1





There are better solutions, as detailed in 1+ answers, but to clarify: graphs[c] = *g is not doing what you think it is.

– jwimberley
Nov 20 '18 at 22:39





There are better solutions, as detailed in 1+ answers, but to clarify: graphs[c] = *g is not doing what you think it is.

– jwimberley
Nov 20 '18 at 22:39












2 Answers
2






active

oldest

votes


















4














You actually don't have to do anything fancy here. You can simply do



Graph* g = &graphs[c];


The reason is that map::operator has the following behavior:




Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.




So if the key has an associated value already, you'll get a reference to that object. If that key does not yet exist, a value will be default constructed and inserted for you, and a reference to that new object will be returned.






share|improve this answer
























  • Even better, it could just be Graph& g = graphs[c], where graphs calls Graph's default constructor, and no memory management is needed.

    – jwimberley
    Nov 20 '18 at 22:37






  • 1





    That is exactly what my answer is stating, the only difference is whether you return a reference or a pointer, the allocation and construction is identical to what you demonstrated in your comment

    – CoryKramer
    Nov 20 '18 at 22:38











  • Yeah, I get that, I was just making a comment to point out the extra niceties your suggestion provides, since the code in the OP's question is leaky...

    – jwimberley
    Nov 20 '18 at 22:41













  • Can I just do Graph g = graphs[c];? Would that be equivalent to the Python code? I started messing with pointers because I thought it was the only way.

    – Rafael
    Nov 20 '18 at 22:45






  • 2





    Graph g = graphs[c]; would copy. Probably not what you're after.

    – user4581301
    Nov 20 '18 at 22:46



















2














Another answer already says the right way to do what you're asking, but I'll address (ha!) why the addresses don't match:



On this line:



    graphs[c] = *g;


You're creating a COPY of the graph you just made with new that g points to, and that copy has a different address. You're then printing the address of the original and the address of the copy, so obviously they're at different addresses.



graphs[c] = ...


This code already does the allocation and construction of a (default) Graph object to be stored inside the map when there isn't one mapped to c already (which you already checked for).. the assignment after that just makes the Graph object it just created look like the one that you had previously created with the call to new.






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%2f53402594%2fdelayed-instantiation-in-c%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














    You actually don't have to do anything fancy here. You can simply do



    Graph* g = &graphs[c];


    The reason is that map::operator has the following behavior:




    Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.




    So if the key has an associated value already, you'll get a reference to that object. If that key does not yet exist, a value will be default constructed and inserted for you, and a reference to that new object will be returned.






    share|improve this answer
























    • Even better, it could just be Graph& g = graphs[c], where graphs calls Graph's default constructor, and no memory management is needed.

      – jwimberley
      Nov 20 '18 at 22:37






    • 1





      That is exactly what my answer is stating, the only difference is whether you return a reference or a pointer, the allocation and construction is identical to what you demonstrated in your comment

      – CoryKramer
      Nov 20 '18 at 22:38











    • Yeah, I get that, I was just making a comment to point out the extra niceties your suggestion provides, since the code in the OP's question is leaky...

      – jwimberley
      Nov 20 '18 at 22:41













    • Can I just do Graph g = graphs[c];? Would that be equivalent to the Python code? I started messing with pointers because I thought it was the only way.

      – Rafael
      Nov 20 '18 at 22:45






    • 2





      Graph g = graphs[c]; would copy. Probably not what you're after.

      – user4581301
      Nov 20 '18 at 22:46
















    4














    You actually don't have to do anything fancy here. You can simply do



    Graph* g = &graphs[c];


    The reason is that map::operator has the following behavior:




    Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.




    So if the key has an associated value already, you'll get a reference to that object. If that key does not yet exist, a value will be default constructed and inserted for you, and a reference to that new object will be returned.






    share|improve this answer
























    • Even better, it could just be Graph& g = graphs[c], where graphs calls Graph's default constructor, and no memory management is needed.

      – jwimberley
      Nov 20 '18 at 22:37






    • 1





      That is exactly what my answer is stating, the only difference is whether you return a reference or a pointer, the allocation and construction is identical to what you demonstrated in your comment

      – CoryKramer
      Nov 20 '18 at 22:38











    • Yeah, I get that, I was just making a comment to point out the extra niceties your suggestion provides, since the code in the OP's question is leaky...

      – jwimberley
      Nov 20 '18 at 22:41













    • Can I just do Graph g = graphs[c];? Would that be equivalent to the Python code? I started messing with pointers because I thought it was the only way.

      – Rafael
      Nov 20 '18 at 22:45






    • 2





      Graph g = graphs[c]; would copy. Probably not what you're after.

      – user4581301
      Nov 20 '18 at 22:46














    4












    4








    4







    You actually don't have to do anything fancy here. You can simply do



    Graph* g = &graphs[c];


    The reason is that map::operator has the following behavior:




    Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.




    So if the key has an associated value already, you'll get a reference to that object. If that key does not yet exist, a value will be default constructed and inserted for you, and a reference to that new object will be returned.






    share|improve this answer













    You actually don't have to do anything fancy here. You can simply do



    Graph* g = &graphs[c];


    The reason is that map::operator has the following behavior:




    Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.




    So if the key has an associated value already, you'll get a reference to that object. If that key does not yet exist, a value will be default constructed and inserted for you, and a reference to that new object will be returned.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 20 '18 at 22:36









    CoryKramerCoryKramer

    74k1188141




    74k1188141













    • Even better, it could just be Graph& g = graphs[c], where graphs calls Graph's default constructor, and no memory management is needed.

      – jwimberley
      Nov 20 '18 at 22:37






    • 1





      That is exactly what my answer is stating, the only difference is whether you return a reference or a pointer, the allocation and construction is identical to what you demonstrated in your comment

      – CoryKramer
      Nov 20 '18 at 22:38











    • Yeah, I get that, I was just making a comment to point out the extra niceties your suggestion provides, since the code in the OP's question is leaky...

      – jwimberley
      Nov 20 '18 at 22:41













    • Can I just do Graph g = graphs[c];? Would that be equivalent to the Python code? I started messing with pointers because I thought it was the only way.

      – Rafael
      Nov 20 '18 at 22:45






    • 2





      Graph g = graphs[c]; would copy. Probably not what you're after.

      – user4581301
      Nov 20 '18 at 22:46



















    • Even better, it could just be Graph& g = graphs[c], where graphs calls Graph's default constructor, and no memory management is needed.

      – jwimberley
      Nov 20 '18 at 22:37






    • 1





      That is exactly what my answer is stating, the only difference is whether you return a reference or a pointer, the allocation and construction is identical to what you demonstrated in your comment

      – CoryKramer
      Nov 20 '18 at 22:38











    • Yeah, I get that, I was just making a comment to point out the extra niceties your suggestion provides, since the code in the OP's question is leaky...

      – jwimberley
      Nov 20 '18 at 22:41













    • Can I just do Graph g = graphs[c];? Would that be equivalent to the Python code? I started messing with pointers because I thought it was the only way.

      – Rafael
      Nov 20 '18 at 22:45






    • 2





      Graph g = graphs[c]; would copy. Probably not what you're after.

      – user4581301
      Nov 20 '18 at 22:46

















    Even better, it could just be Graph& g = graphs[c], where graphs calls Graph's default constructor, and no memory management is needed.

    – jwimberley
    Nov 20 '18 at 22:37





    Even better, it could just be Graph& g = graphs[c], where graphs calls Graph's default constructor, and no memory management is needed.

    – jwimberley
    Nov 20 '18 at 22:37




    1




    1





    That is exactly what my answer is stating, the only difference is whether you return a reference or a pointer, the allocation and construction is identical to what you demonstrated in your comment

    – CoryKramer
    Nov 20 '18 at 22:38





    That is exactly what my answer is stating, the only difference is whether you return a reference or a pointer, the allocation and construction is identical to what you demonstrated in your comment

    – CoryKramer
    Nov 20 '18 at 22:38













    Yeah, I get that, I was just making a comment to point out the extra niceties your suggestion provides, since the code in the OP's question is leaky...

    – jwimberley
    Nov 20 '18 at 22:41







    Yeah, I get that, I was just making a comment to point out the extra niceties your suggestion provides, since the code in the OP's question is leaky...

    – jwimberley
    Nov 20 '18 at 22:41















    Can I just do Graph g = graphs[c];? Would that be equivalent to the Python code? I started messing with pointers because I thought it was the only way.

    – Rafael
    Nov 20 '18 at 22:45





    Can I just do Graph g = graphs[c];? Would that be equivalent to the Python code? I started messing with pointers because I thought it was the only way.

    – Rafael
    Nov 20 '18 at 22:45




    2




    2





    Graph g = graphs[c]; would copy. Probably not what you're after.

    – user4581301
    Nov 20 '18 at 22:46





    Graph g = graphs[c]; would copy. Probably not what you're after.

    – user4581301
    Nov 20 '18 at 22:46













    2














    Another answer already says the right way to do what you're asking, but I'll address (ha!) why the addresses don't match:



    On this line:



        graphs[c] = *g;


    You're creating a COPY of the graph you just made with new that g points to, and that copy has a different address. You're then printing the address of the original and the address of the copy, so obviously they're at different addresses.



    graphs[c] = ...


    This code already does the allocation and construction of a (default) Graph object to be stored inside the map when there isn't one mapped to c already (which you already checked for).. the assignment after that just makes the Graph object it just created look like the one that you had previously created with the call to new.






    share|improve this answer






























      2














      Another answer already says the right way to do what you're asking, but I'll address (ha!) why the addresses don't match:



      On this line:



          graphs[c] = *g;


      You're creating a COPY of the graph you just made with new that g points to, and that copy has a different address. You're then printing the address of the original and the address of the copy, so obviously they're at different addresses.



      graphs[c] = ...


      This code already does the allocation and construction of a (default) Graph object to be stored inside the map when there isn't one mapped to c already (which you already checked for).. the assignment after that just makes the Graph object it just created look like the one that you had previously created with the call to new.






      share|improve this answer




























        2












        2








        2







        Another answer already says the right way to do what you're asking, but I'll address (ha!) why the addresses don't match:



        On this line:



            graphs[c] = *g;


        You're creating a COPY of the graph you just made with new that g points to, and that copy has a different address. You're then printing the address of the original and the address of the copy, so obviously they're at different addresses.



        graphs[c] = ...


        This code already does the allocation and construction of a (default) Graph object to be stored inside the map when there isn't one mapped to c already (which you already checked for).. the assignment after that just makes the Graph object it just created look like the one that you had previously created with the call to new.






        share|improve this answer















        Another answer already says the right way to do what you're asking, but I'll address (ha!) why the addresses don't match:



        On this line:



            graphs[c] = *g;


        You're creating a COPY of the graph you just made with new that g points to, and that copy has a different address. You're then printing the address of the original and the address of the copy, so obviously they're at different addresses.



        graphs[c] = ...


        This code already does the allocation and construction of a (default) Graph object to be stored inside the map when there isn't one mapped to c already (which you already checked for).. the assignment after that just makes the Graph object it just created look like the one that you had previously created with the call to new.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 20 '18 at 22:57

























        answered Nov 20 '18 at 22:42









        xaxxonxaxxon

        14.4k43060




        14.4k43060






























            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%2f53402594%2fdelayed-instantiation-in-c%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

            MongoDB - Not Authorized To Execute Command

            How to fix TextFormField cause rebuild widget in Flutter

            in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith