Thread: References vs Pointer vs copying and storing stuff in classes

  1. #1
    Registered User
    Join Date
    Aug 2006
    Posts
    14

    References vs Pointer vs copying and storing stuff in classes

    Hi,
    I'm having a bit of trouble deciding on which way I should pass objects to other objects. There appears to be 3 main ways of doing it: pass by reference, pass by value and pass by pointer. I understand how each of these works but I don't know when to use each of them. For example, take this bit of code:
    Code:
    #include "MainClass.h"
    #include "OtherClass.h"
    MainClass mClass;
    
    void init() {
        OtherClass oc;
        // do stuff with oc
        mClass.setOtherClassUsingPassByValue(oc);
    }
    
    int main() {
        init();
        mClass.doStuffWithOtherClass();
        return 0;
    }
    This is really simple, but am I right in saying it wouldn't be a good design if OtherClass was fairly big (memory wise)?

    Another way to do it would be to use pointers (same code except init method):
    Code:
    void init() {
        OtherClass* oc = new OtherClass();
        // do stuff with oc
        mClass.setOtherClassUsingPassByPointer(oc); // mClass takes ownership of oc
    }
    This is also simple, but I've read in numerous places that you should avoid pointers wherever possible and use references, instead of pointers in methods of objects.

    So this is a reference way:
    Code:
    void init() {
        OtherClass oc;
        // do stuff with oc
        mClass.setOtherClassUsingReference(oc); // mClass takes ownership of oc
    }
    But Im not sure if this way would work as would oc delete itself when init finished? To fix that problem, I could do:
    Code:
    void init() {
        OtherClass& oc = *new OtherClass();
        // do stuff with oc
        mClass.setOtherClassUsingReference(oc); // mClass takes ownership of oc
    }
    But that, while it would probably work, seems messy (I've never seen *new used before). So I was wondering what was the general way of solving this problem.

    Also, a similar problem, how do you normally store objects inside a class (eg MainClass)? I.e as a pointer, reference or value and when is each appropriate?
    Thanks!

  2. #2
    Devil's Advocate SlyMaelstrom's Avatar
    Join Date
    May 2004
    Location
    Out of scope
    Posts
    4,079
    The most commonly accepted way of passing an object is to use a constant reference. This gives the argument the advantage of not being editable that passing by value has without the disadvantage of actually having to make a copy of the object which can be time and memory consuming.
    Code:
    void myFunc(const myClass& obj1);
    Sent from my iPadŽ

  3. #3
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >I understand how each of these works but I don't know when to use each of them.
    Keeping things as simple as possible, pass by reference when you want to change the object and pass by const reference otherwise. Pass by value should be avoided for non-primitive types and pass by pointer has been largely replaced by pass by reference. You can pass pointers by reference as well, so no worries there. This guideline is usually all you need.
    My best code is written with the delete key.

  4. #4
    Registered User
    Join Date
    Aug 2006
    Posts
    14
    > The most commonly accepted way of passing an object is to use a constant reference
    So I should probably stick with the last two then. But is my code for the last two correct?

  5. #5
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    With this code
    Code:
    OtherClass& oc = *new OtherClass();
    you have no way to delete the memory.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  6. #6
    Devil's Advocate SlyMaelstrom's Avatar
    Join Date
    May 2004
    Location
    Out of scope
    Posts
    4,079
    As Prelude says, you'll basically have one of two things.
    Code:
    void myFunc(const myClass& foo) {
     // Code that doesn't edit the argument
    }
    
    /* or */
    
    void myFunc(myClass& foo) {
     // Code that does plan to edit the argument
    }
    
    /* Oh by the way, you shouldn't have the same function name for both as the 
       second will overwrite the first */
    That should basically be it. The two things you're likely going to pass to these functions are objects and pointers to objects, which should be passed as myFunc(myObj) and myFunc(*myObj), respectively. That last example in your post is way wrong.
    Last edited by SlyMaelstrom; 08-31-2006 at 09:00 AM.
    Sent from my iPadŽ

  7. #7
    Registered User
    Join Date
    Aug 2006
    Posts
    14
    Quote Originally Posted by dwks
    With this code
    Code:
    OtherClass& oc = *new OtherClass();
    you have no way to delete the memory.
    Doesn't
    Code:
     delete &oc
    delete it?

    Oh and thanks SlyMaelstrom for the sample code but I understand that part. The problem I'm having is with the using the function. Could you show me how you do it?

  8. #8
    Devil's Advocate SlyMaelstrom's Avatar
    Join Date
    May 2004
    Location
    Out of scope
    Posts
    4,079
    Quote Originally Posted by Monkeymagic
    Oh and thanks SlyMaelstrom for the sample code but I understand that part. The problem I'm having is with the using the function. Could you show me how you do it?
    A reference acts exactly like a plain old object passed by value and is used the same way. Now, keep in mind, in your code
    Code:
    void init() {
        OtherClass oc;  // This object is temporary and will be deleted at the end of the function
        // do stuff with oc
        mClass.setOtherClassUsingPassByReference(oc);  // Which means at this point, 
                           // you'd better be making something permenant out of that argument.
    } // Cause it's gone here
    Last edited by SlyMaelstrom; 08-31-2006 at 09:11 AM.
    Sent from my iPadŽ

  9. #9
    Registered User
    Join Date
    Aug 2006
    Posts
    14
    Quote Originally Posted by SlyMaelstrom
    Code:
    void init() {
        OtherClass oc;  // This object is temporary and will be deleted at the end of the function
        // do stuff with oc
        mClass.setOtherClassUsingPassByValue(oc);  // Which means at this point, 
                           // you'd better be making something permenant out of that argument.
    } // Cause it's gone here
    Yes I thought something like that would happed (although in another bit of code I did that and it compiled an ran perfectly; probably luck that the stack wasn't wiped over or something.

    So there seems to be so many ways to do it wrong, so I'm still looking for the right way.

  10. #10
    Devil's Advocate SlyMaelstrom's Avatar
    Join Date
    May 2004
    Location
    Out of scope
    Posts
    4,079
    Quote Originally Posted by Monkeymagic
    So there seems to be so many ways to do it wrong, so I'm still looking for the right way.
    I don't know what you're looking for... I told you the right way to do it. Let me make a big example for you
    Code:
    // Let's assume your main class contains an otherClass object.
    class otherClass {
       public:
          otherClass() {}
          otherClass(int x, int y) : ocX(x), ocY(y) {}
          void setX(int x) { ocX = x; }
          void setY(int y) { ocY = y; }
          int getX() { return ocX; }
          int getY() { return ocY; }
       private:
          int ocX, ocY;
    };
    
    class mainClass {
        public:
            void setOtherClass(otherClass& tempObj) { // Pass by reference
                  obj1.setX(tempObj.getX());
                  obj1.setY(tempObj.getY());
            }
            void doStuffwithotherclass() { /* Whatever you want here */ }
       private:
           otherClass obj1;
    };
    
    mainClass myMain;   // Your global mainClass... ...
    
    void init() {
        otherClass temp(0,0);  // Make an object sets X and Y to zero
        /* You could have also done it with setters here */
        myMain.setOtherClass(temp); // Passes the temp object to the mainClass
        // Or more simply would be myMain.setOtherClass(otherClass(0,0));
        // ...but this function is pretty much a waste of time no matter how you go
        // about it.
    };
    
    int main() {
        init();
        myMain.doStuffwithotherclass();
    
        return 0;
    }
    There...

    Now this code is pretty silly as I would basically just cut out the init function and initialize in main or better yet, the mainClass constructor, but whatever... I just tried to keep it looking like your example so you can understand whatever you weren't getting from the other posts.
    Last edited by SlyMaelstrom; 08-31-2006 at 09:30 AM.
    Sent from my iPadŽ

  11. #11
    Registered User
    Join Date
    Aug 2006
    Posts
    14
    Thanks for that. The main problem I am having is that I don't want to copy OtherClass when I don't need to (because I'm assuming it is a large class). But in your code in the setOtherClass method, you copy all the of the members of the passed value to the stored value. Wouldn't this be slow if OtherClass was large?

    Also, there might be situations where you want to be able to modify the OtherClass in MainClass by changing (in this case temp) the passed to object after it was passed to MainClass

    What I am looking for is code that can work with
    Code:
    class mainClass {
        public:
            void setOtherClass(const otherClass& tempObj) {
                  obj1 = &tempObj;
            }
            void doStuffwithotherclass() { /* Whatever you want here */ }
       private:
           otherClass* obj1;  // now a pointer
    };
    Note that this class would now need a destructor to delete obj1 but thats not the problem. Now how do you call that method? The old init now won't work as the OtherClass obj1 is pointing to would be deleted as soon as the method quit. Is it even possible what I want to do?

  12. #12
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Just call it like this:
    Code:
    otherClass *c = new otherClass;
    setOtherClass(*c);
    // don't delete c
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  13. #13
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    This appears to be one of the rare cases that you should be using pointers everywhere. You are creating the OtherClass instance inside of init(), and you want it to live past then end of that function. You need dynamic allocation with new to do that. Then, since it is allocated with new, you need something to take ownership of the object and delete it when it is no longer needed. In this case that will apparently be the MainClass object.

    So, the MainClass class should store a pointer to an OtherClass. It should set it to null in the constructor and delete it in the destructor. The setOtherClass function should take a pointer and just save the pointer to the MainClass' pointer member variable. Using references in this case only complicates the issue (unless there are some other factors involved that have not yet been mentioned).

  14. #14
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Quote Originally Posted by Monkeymagic
    Quote Originally Posted by dwks
    With this code
    Code:
    OtherClass& oc = *new OtherClass();
    you have no way to delete the memory.
    Doesn't
    Code:
     delete &oc
    delete it?
    I don't think so. I could be wrong, though -- I've never used dynamically allocated references myself. Pointers always seemed like a better idea.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  15. #15
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Yes, it would delete it. It's just unnecessarily complex IMO.

Popular pages Recent additions subscribe to a feed