Friday, January 29, 2010

Copy Constructor- what, why and types.

The compiler not only creates a default constructor for you if you do not specify your own. It provides three special member functions in total that are implicitly declared if you do not declare your own. These are the copy constructor, the copy assignment operator, and the default destructor.

When copies of objects are made
A copy constructor is called whenever a new variable is created from an object. This happens in the following cases (but not in assignment).

A variable is declared which is initialized from another object, eg,
Person q("Mickey"); // constructor is used to build q.
Person r(p); // copy constructor is used to build r.
Person p = q; // copy constructor is used to initialize in declaration.
p = q; // Assignment operator, no constructor or copy constructor.
A value parameter is initialized from its corresponding argument.
f(p); // copy constructor initializes formal value parameter.
An object is returned by a function.
C++ calls a copy constructor to make a copy of an object in each of the above cases. If there is no copy constructor defined for the class, C++ uses the default copy constructor which copies each field, ie, makes a shallow copy.

Don't write a copy constructor if shallow copies are ok
If the object has no pointers to dynamically allocated memory, a shallow copy is probably sufficient. Therefore the default copy constructor, default assignment operator, and default destructor are ok and you don't need to write your own.

If you need a copy constructor, you also need a destructor and operator=
If you need a copy constructor, it's because you need something like a deep copy, or some other management of resources. Thus is is almost certain that you will need a destructor and override the assignment operator.

Copy constructor syntax
The copy constructor takes a reference to a const parameter. It is const to guarantee that the copy constructor doesn't change it, and it is a reference because a value parameter would require making a copy, which would invoke the copy constructor, which would make a copy of its parameter, which would invoke the copy constructor, which ...

Here is an example of a copy constructor for the Point class, which doesn't really need one because the default copy constructor's action of copying fields would work fine, but it shows how it works.

//=== file Point.h =============================================
class Point {
public:
. . .
Point(const Point& p); // copy constructor
. . .
//=== file Point.cpp ==========================================
. . .
Point::Point(const Point& p) {
x = p.x;
y = p.y;
}
. . .
//=== file my_program.cpp ====================================
. . .
Point p; // calls default constructor
Point s = p; // calls copy constructor.
p = s; // assignment, not copy constructor.
Difference between copy constructor and assignment
A copy constructor is used to initialize a newly declared variable from an existing variable. This makes a deep copy like assignment, but it is somewhat simpler:

There is no need to test to see if it is being initialized from itself.
There is no need to clean up (eg, delete) an existing value (there is none).
A reference to itself is not returned.

Copy constructor is
a constructor function with the same name as the class
used to make deep copy of objects.
There are 3 important places where a copy constructor is called.

When an object is created from another object of the same type
When an object is passed by value as a parameter to a function
When an object is returned from a function
If a copy constructor is not defined in a class, the compiler itself defines one. This will ensure a shallow copy. If the class does not have pointer variables with dynamically allocated memory, then one need not worry about defining a copy constructor. It can be left to the compiler's discretion.

But if the class has pointer variables and has some dynamic memory allocations, then it is a must to have a copy constructor.

For ex:
class A //Without copy constructor
{
private:
int x;
public:
A() {A = 10;}
~A() {}
}
class B //With copy constructor
{
private:
char *name;
public:
B()
{
name = new char[20];
}
~B()
{
delete name[];
}
//Copy constructor
B(const B &b)
{
name = new char[20];
strcpy(name, b.name);
}
};
Let us Imagine if you don't have a copy constructor for the class B. At the first place, if an object is created from some existing object, we cannot be sure that the memory is allocated. Also, if the memory is deleted in destructor, the delete operator might be called twice for the same memory location.

This is a major risk. One happy thing is, if the class is not so complex this will come to the fore during development itself. But if the class is very complicated, then these kind of errors will be difficult to track

No comments:

Post a Comment