A copy constructor is a constructor that has a certain, fixed signature. Like other constructors, the copy constructor cannot be called explicitly. The copy constructor is called implicitly when the C++ language dictates that a copy of an object is required.
If a class does not define a copy constructor, a default copy constructor is used. The default copy constructor performs a byte-by-byte copy from the existing object to the new object. In many simple cases the default copy constructor is adequate. However, as the examples below will show, the default copy constructor is often inadequate. In addition, many consider it good style to always define a copy constructor even if it has the same effect as the default copy constructor.
An object will be copied in two circumstances: (1) when a new object is declared and initialized using an existing object, and (2) when an object is passed as a parameter "by copy". These two circumstances are illustrated in the following code:
Frame window1(Location(100, 100), Shape (200,300));
Frame window2(Location(100, 100), Shape (200,300));
Message originalMsg("Hello World");
Message copiedMsg( originalMsg ); // copy constructor used
...
window1.Display(originalMsg); // copy constructor used
window2.Display(copiedMsg); // copy constructor used
In this example, the declaration of the Message object "copiedMsg" uses
the copy constructor defined for the Message class. The initial values
for the data members of the object "copiedMsg" are initialized based
on the data members in the object "originalMsg". The call on the
Display method passes a Message object by copy. On each of the two
calls to Display, the copy constructor for the Message class will be
used to generate a copy of the object being passed as an argument.
The example above will be used to show why the default copy constructor is inadequate for Message class objects. Recall that the implementation of the Message class uses a character string (a char*) to hold a pointer that defines the text to be displayed on the screen. To avoid a memory leak, the destructor for the Message class appropriately deletes this character string when the Message object is deleted. The relevant portion of the Message class is:
class Message {
private:
char* message;
...
public:
...
~Message(); // delete message
};
Message::~Message(){ delete message; }
When a copy is made of a Message object using the default copy
constructor, the pointer (message), but not the string to which it
points, is copied. This default copying results in the following
situation:
| Shared Data |
|---|
|
Both objects point to the same place in memory. As long as both objects exists, there is no problem. However, if either of the objects is deleted the character string will be deallocated by that object's destructor, leaving the other object pointing to a place in memory that has an undefined content.
The errors that can result from this situation are as follows. In the case above, the first call on the Display method will create a copy of the originalMsg object. This copy will be destructed at the end of the Display method. Thus, both the originalMsg object and the copiedMsg object are pointing to memory with undefined content. When the second call on Display is made one of three things can happen:
The copy constructor for the Message class illustrates how a copy constructor is defined:
class Message {
private:
...
public:
Message(const Message& other); // copy constructor
};
The copy constructor has a single argument - a reference to an object
of the same class (i.e., the Message class in this case) that is not
changed (i.e., it is declared "const"). The input argument ("other")
is declared "const" because the copy constructor does not need to
change the argument to initialize the new object.
The code for the Message class' copy constructor is as follows:
Message::Message(const Message& other) {
message = copystring(other.message); }
This constructor copies the character string that is defined by the
other object. In this case, when each object is destructed only its
own copy of the character string will be deleted. No memory leaks are
created and no "dangling" pointers occur.
|
|
| Exercises |
Last Updated: February 26, 1996 / kafura@cs.vt.edu