Thread: Help me understand copying better

  1. #1
    Registered Abuser
    Join Date
    Sep 2007
    Location
    USA/NJ/TRENTON
    Posts
    127

    Help me understand copying better

    I understand the difference between the copy ctor & the assignment operator and when each is used
    Code:
    SomeObject object2(object1); // This calls the copy ctor
    
    SomeObject object2 = object1; // This calls the assignment operator
    I'm hoping someone can clear up a few things for me. I'm sure I've been to any of the major websites you might direct me to explaining these things, and I'm sure you're tired of reiterating this discussion, but pleez someone explain some of the following things that I'll comment in the code:
    Code:
    class MyClass{
    
        public:
    
            MyClass(const MyClass& rhs) : m_someData(rhs.m_someData), m_my ClassPtr(rhs.m_myClassPtr) {};    // Is this the correct copy ctor?
    
            MyClass& operator=(const MyClass& rhs){
    
                if ( this != &rhs ){    //  What exactly does this line do?
    
                     m_someData = rhs.m_someData;
                     m_myClassPtr = rhs.m_myClassPtr;  // Is this correct?
                }
    
                return *this;
            
            };    // Is my assignment operator correct or horribly misguided?
    
        private:
    
            int m_someData;
    
            MyClass* m_myClassPtr;
    };
    Your simplest explanation breaking this down is much appreciated.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Code:
    SomeObject object2 = object1; // This calls the assignment operator
    Actually, this is copy construction, not copy assignment. An example of copy assignment would be:
    Code:
    SomeObject object2;
    object2 = object1; // This calls the assignment operator
    Is this the correct copy ctor?
    Not likely. You are just doing shallow copying of pointers, but perhaps a deep copy is needed.

    What exactly does this line do?
    Check for self-assignment.

    Is this correct?
    Same thing as in the copy ctor: not likely unless you really want shallow copying. If you do want a shallow copying then you do not even need to write the copy constructor and copy assignment operator since the compiler generated versions will do exactly that.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered Abuser
    Join Date
    Sep 2007
    Location
    USA/NJ/TRENTON
    Posts
    127
    thank you laserlight, but then how DO you write them to get the DEEP copies?

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    thank you laserlight, but then how DO you write them to get the DEEP copies?
    Eh, looking more carefully, I notice that you are declaring MyClass itself. Consequently, you probably just want association, not composition, so deep copying may not be the right thing to do. It is hard to say what is correct unless the expected copying semantics is known.

    Then, it depends on what the pointer points to. A single object? An array of objects? Before getting to all this, you should of course consider if using a (standard) container is the right thing.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered Abuser
    Join Date
    Sep 2007
    Location
    USA/NJ/TRENTON
    Posts
    127
    I'm guessing that this whole copying business really only applies to pointers right?

    For my example I'll assume that the copying is only one to one (no arrays or linked-lists)

    Does that mean you need to use your accessor/mutator methods to get the DEEP copy?

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    The need for a deep copy or shallow copy can only be determined by understanding the USE of the class and the meaning of any pointers inside the object [and any sub object]. If you use a shallow copy, the copied content has the same pointer [points to the same object], whilst a deep copy creaes a NEW object that has the same content as the object in the original class. Which do you want? Depends on what you are doing and how the class is intended to be used.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Registered Abuser
    Join Date
    Sep 2007
    Location
    USA/NJ/TRENTON
    Posts
    127
    I want to know how to write the deep copy (what is being pointed to)

    If I think back to my template linked list class, the value in each node was copied using this method:
    Code:
    for(Iterator i = begin(); i != end(); ++i){
    
          push_back(*i);  // The copy was made with the dereference operator here
    }
    Likewise, if a very simple object (as in my OP) was in this situation:
    Code:
    MyClass a;
    MyClass b;
    a = b;
    how then do I write the copy ctor/assignment optor to make the deep copy?

  8. #8
    Registered Abuser
    Join Date
    Sep 2007
    Location
    USA/NJ/TRENTON
    Posts
    127
    How about this?
    Code:
    class MyClass{
    
    public:
    
    MyClass& operator=(const MyClass& rhs){
    
        MyClass* temp = new MyClass(*rhs.m_ptr);
        delete m_ptr;
        m_ptr = temp;
        return *this;
    }
    
    
    private:
    
        MyClass* m_ptr;
    };
    Does this work correctly?

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Does this work correctly?
    I dont think so. It will fail if m_ptr is a null pointer (i.e., it cannot be validly dereferenced). But if m_ptr is never a null pointer, then you have an infinitely long hierarchy of MyClass objects owning other MyClass objects.

    Let's cut this self ownership with a simpler example:
    Code:
    class IntVector {
    public:
        typedef unsigned int size_type;
    
        // Default constructor.
        // ...
    
        // Copy constructor.
        IntVector(const IntVector& other) : m_size(other.m_size), m_capacity(other.m_capacity) {
            m_data = new int[m_capacity];
            // Do the deep copying.
            for (size_type i = 0; i < m_size; ++i) {
                m_data[i] = other.m_data[i];
            }
        }
    
        // Copy assignment operator.
        IntVector& operator=(const IntVector& rhs) {
            // Optional (in this case) check for self assignment.
            if (this != &rhs) {
                IntVector temp(rhs);
                swap(temp);
            }
            return *this;
        }
    
        // Destructor.
        ~IntVector() {
            delete[] m_data;
        }
    
        // Member swap.
        void swap(IntVector& other) {
            using std::swap;
            swap(m_data, other.m_data);
            swap(m_size, other.m_size);
            swap(m_capacity, other.m_capacity);
        }
    
        // ... other member functions
        // ...
    private:
        int*      m_data;     // Array of items.
        size_type m_size;     // Number of items.
        size_type m_capacity; // Maximum number of items until expansion is needed.
    };
    Last edited by laserlight; 11-11-2007 at 12:47 PM. Reason: Fixed typo.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User
    Join Date
    Nov 2007
    Posts
    19
    Im a little rusty but correct me if im right wrong guys, if we define a assignment operator =

    for instance

    Code:
    class Test
    {
    ....
    Test operator = (const Test & c)
    {...}
    };
    I know in VS if i do something like
    Code:
    Test a;
    Test b(a);
    The compiler will then use the overloaded operator = as a copy constructor, without return the pointer offcourse

    My question is, is that standard c++ or just Microsoft implementation specific ?

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    The compiler will then use the overloaded operator = as a copy constructor, without return the pointer offcourse
    It wont. The copy constructor and copy assignment operator are two different things.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by force of will View Post
    The compiler will then use the overloaded operator = as a copy constructor, without return the pointer offcourse
    It doesn't. It uses a built-in assignment operator instead.
    Unless you can show an example of where and how this happens.

  13. #13
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by laserlight View Post
    It wont. The copy constructor and copy assignment operator are two different things.
    Yes. The reason it isn't possible is that the assignment operator is responsible for first releasing the resources currently hend by the thing on the left hand side, before assigning copies of the resources form the right hand side.
    If the compiler were to try and use the assignment operator in place of the copy-constructor then it would encounter code that releases said resources, which since the object has not yet been constructed, may contain gibberish pointers, and boom you get a crash!


    Also note that one optimisation compilers are specifically allowed to make with regards to this from the orignal post:
    Code:
    SomeObject object2 = object1;
    In that case the compiler is allowed to also use the copy-constructor, instead of a call to the default constructor followed by a call to the assignment operator. So you can't actually say that it will call the assignment operator. It's compiler dependent.
    This optimisation only applies when you use assignment in the declaration. It is one of the rare cases where the compiler is allowed to do such things.

    You can however say this for certain:
    Code:
    SomeObject object2;
    object2 = object1; // This calls the assignment operator
    Last edited by iMalc; 11-11-2007 at 11:51 PM.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  14. #14
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    Quote Originally Posted by Elysia View Post
    It doesn't. It uses a built-in assignment operator instead.
    No - force of will's code calls the copy constructor. The assignment operator will never get called in the small snip of code he posted. In this case, it'll be one provided by the compiler, since he didn't define one. (His assignment operator probably ought to return "Test &" as well...)

    In more depth:
    Code:
    #include <iostream>
    using namespace std;
    
    class Test {
    	Test &operator = (const Test &t) {
    		cout << "assign!" << endl;
    		return *this;
    	}
    };
    
    int main() {
    	Test a;
    	Test b(a);
    
    	int x;
    	cin >> x;
    	return 0;
    }
    Will print out nothing.
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  15. #15
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Ahaha, I was thinking of something else. Yes, it calls the copy constructor and not the assignment operator.

Popular pages Recent additions subscribe to a feed