Aug 26

A C++ compiler implicitly creates a copy constructor and an assignment operator for any class that does not explicitly define them.

class Widget
{
public:
    Widget( Gadget* gadget )
    : gadget_( gadget ) {}

    ~Widget() { delete gadget_; }

private:
    Gagdet* gadget_;
};

 
Here, we have not explicitly defined the copy constructor or the assignment operator, so the compiler will add them, resulting a class like this:

class Widget
{
public:
    Widget( Gadget* gadget )
    : gadget_( gadget ) {}

    ~Widget() { delete gadget_; }

    Widget( const Widget& widget )
    : gadget_( widget.gadget_ ) {}

    Widget& operator=( const Widget& widget )
    {
        gadget_ = widget.gadget_;
        return *this;
    }

private:
    Gagdet* gadget_;
};

 
Consider the following code fragment that uses the Widget class:

int main()
{
    Gadget* gadget = new Gadget;
    Widget* w1 = new Widget( gadget );

    Widget w2 = *w1;    // Copy using the assignment operator
    Widget w3( *w1 );   // Copy using the copy constructor

    return 0;
}

 
The default copy constructor and assignment operator copy all member variables from an object to another as-is. The problem arises when an object has a pointer to some other object; gadget_ in this case. When copying or assigning an object using the automatically generated functions, only the pointer value is copied. Both the objects’ member variables now point to the same object. Now, when the original object is destroyed, it deletes the widget_ member object whose pointer it held. The result is that the copied object’s pointer now points to deleted memory, and all bets are off.

When you have classes that contain pointers to other objects, consider if it is ok to just copy the pointers using the automatically generated copy constructor and assignment operator. If the pointed-to object ownership is not within the objects being copied, memberwise copying using the default copy constructor and copy assignment is ok. But it the objects own the data behind the pointers, you’ll want to either disable the copy constructor and assignment operator (by making them protected/private), or make sure the object is actually cloned (or deep-copied) so that the new object is self-contained. This means that the pointers cannot point to the same objects but new ones instead, which are created upon cloning the object in the copy constructor or assignment operator.

Leave a Reply

preload preload preload