Thursday, January 17, 2008

copy constructor

the copy constructor's signature is usually X::X(const X&). Pronounce X-X-ref (pretend the const is silent).

When an object is passed by value, returned by value, or explicitly copied, copy constructor is invoked.

#include <iostream>
using namespace std;

class X {
public:
X() throw();
X(const X&) throw();
};

X::X() throw() { cout << "default constructor\n"; }
X::X(const X&) throw() { cout << "copy constructor\n"; }

X userCode(X b) throw() //<-- Pass by value
{
X c = b; //<-- Explicit copy
return c;
} //<-- Return by value
int main()
{
X a;
cout << "calling userCode()\n";
X d = userCode(a);
cout << "back in main()\n";
}
//default constructor <-- a in main()
//calling userCode()
//copy constructor <-- b in userCode()
//copy constructor <-- c in userCode()
//copy constructor <-- 4 in main()
//back in main()

Again, copy constructor happens in following cases:
  • When an object is create from another object during initialization (Class a = b)
  • When an object is created from another object as a parameter to a constructor (Class a(b))
  • When an object is passed by value as an argument to a function (function(Class a))
  • When an object is return from a function (Class a; ? return a;)
  • When an exception is thrown using this object type (Class a; ?. throw a;)
A copy constructor can be either user defined or compiler defined. If the user does not define a copy constructor, then the default compiler defined copy constructor will be invoked during object copy scenarios. The default copy constructor is a bit-by-bit (member wise) copy. But often you will encounter situations where this is not desirable since this is just a shallow copy and sometimes you do not want an exact copy or you may want to do some custom resource management.

Class t1;
Class t2=t1; // Copy Constructor is invoked
Class t3;
t3=t1; // Assignment Operator is invoked

In the Code snippet above, the constructor is invoked twice, during the creation of objects t1 and t3. (Creation of t2 invokes the copy constructor). The destructor is invoked 3 times though. In cases like these, if the constructor allocates memory and the destructor frees it, you will see the t2's destructor will try to delete already deleted memory, if t1 is destroyed before t2 or vice-versa. To prevent this, a user defined copy constructor needs to be provided. which doesn't do a simple bit-by-bit but rather assigns memory specifically for the object and does a deep copy if required. [update: 4/27/08, some source from openasthra] [update: 8/15/08, was asked what happened if remove '&' in X::X(const X&)]


No comments:

Post a Comment