Flylib.com

Books Software

 
 
 

FAQ 20.06 What is the purpose of a copy constructor?

FAQ 20.06 What is the purpose of a copy constructor?

It initializes an object by copying the state from another object of the same class.

Whenever an object is copied, another object (the copy) is created, so a constructor is called (see FAQ 20.02). This constructor is called the copy constructor. If the class of the object being copied is X , the copy constructor's signature is usually X::X(const X&) .

One way to pronounce X(const X&) is X-X-ref ( pretend the const is silent). The first X refers to the name of the member function, and the X -ref refers to the type of the parameter. Some people prefer the shorthand X-X-ref to the phrase copy constructor.

In the following example, the copy constructor is MyString::MyString(const MyString&) . Notice how it initializes the new MyString object to be a copy of the source MyString object.

#include <new>
#include <cstring>
using namespace std;
class MyString {
public:
  MyString(const char* s) throw(bad_alloc);

<-- 1

MyString(const MyString& source) throw(bad_alloc);

<-- 2

~MyString() throw();

<-- 3

MyString& operator= (const MyString& s)
                       throw(bad_alloc);

<-- 4

protected:
  unsigned len_;   // ORDER DEPENDENCY; see FAQ 22.10
  char*    data_;
};

MyString::MyString(const char* s) throw(bad_alloc)
: len_(strlen(s))
, data_(new char[len_+1])
{ memcpy(data_, s, len_+1); }

MyString::MyString(const MyString& source) throw(bad_alloc)
: len_(source.len_)
, data_(new char[source.len_+1])
{ memcpy(data_, source.data_, len_+1); }

MyString::~MyString() throw()
{ delete[] data_; }

int main()
{
  MyString a = "xyzzy"; //Calls MyString::MyString(const char*)
  MyString b = a;       //Calls MyString::MyString(const MyString&)
}

(1) ctor to promote a const char*

(2) Copy constructor

(3) Destructor

(4) Assignment operator

FAQ 20.07 When is a copy constructor invoked?

When an object is passed by value, returned by value, or explicitly copied . Here is an example showing all three situations.

#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()

<-- 1

{
  X c = b;

<-- 2

return c;
}

<-- 3

int main()
{
  X a;
  cout << "calling userCode()\n";
  X d = userCode(a);
  cout << "back in main()\n";
}

(1) Pass by value: Copy main()'s a to b

(2) Explicit copy: Copy from b to c

(3) Return by value: Copy from c to main()'s d

The (annotated) output of this program is

default constructor

<-- 1

calling userCode()
copy constructor

<-- 2

copy constructor

<-- 3

copy constructor

<-- 4

back in main()

(1) main()'s a

(2) userCode()'s b

(3) userCode()'s c

(4) main()'s d

Note that pass- by-value calls the copy constructor if the caller supplies another object of the same class. Supplying something else may invoke a different constructor. Similar comments apply to return-by-value.