Do not carry away with the title “All about copy constructor in C++ with example”. In this article, I am not going to describe what copy constructor in C++ is. There is plenty of material available for that over the internet. Rather we will discuss why, where & how it used, how compiler synthesizes it for you and in what scenarios it called or not synthesized.

Why: Copy Constructor

The simple answer is to copy the data within the same data types, but if you want more concrete idea then see below image:

All about copy constructor in C++

Note: Color represents assembly generated by the compiler for a corresponding C expression

  • As you can see, for creating a copy within the same primitive data types like char, int, float, long double, etc. compiler has special instructions.
  • But when you declare user-defined data type i.e. class/struct. The compiler does not have instruction for that because you are the owner of your type, so you have to define the copy operation in special member function called copy constructor suggesting compiler the way you want to copy.
  • Whenever the situation of copy occurs compiler will simply substitute that expression with your copy constructor method.

Where: Copy Constructor

  • Object initialization by another object of the same class/type.
1
2
3
4
5
class X { ... };
X x;

// Copy constructor will be called
X xx = x;
  • When an object passed as an argument to a function
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
extern void foo( X x );
void bar()
{
  X xx;

  // Copy constructor will be called
  foo( xx );

  // ...
}
  • When a function returns a class object
1
2
3
4
5
6
7
8
X foo_bar()
{
  X xx;
  // ...;

  // Copy constructor will be called
  return xx;
}

Not: Copy Constructor

  • The compiler will not synthesize copy constructor if class having a base class or sub-object with the deleted copy constructor.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
struct base {
    base() = default;
    base(const base&) = delete;
};

struct derived : public base{ };

int main()
{
    derived d1;
    derived d2(d1);
    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
error: call to implicitly-deleted copy constructor of
      'derived'
  derived d2(d1);
          ^  ~~
note: copy constructor of 'derived' is implicitly deleted
      because base class 'base' has a deleted copy constructor
struct derived : public base{ };
                 ^
note: 'base' has been explicitly marked deleted here
    base(const base&) = delete;
    ^
1 error generated.
compiler exit status 1

How: Bitwise Copy & Memberwise Copy

1
2
3
4
5
6
7
8
9
#include "Word.h"

Word noun( "block" );

void foo()
{
  Word verb = noun;
  // ...
}
  • If class word defined as follows, then it exhibits bitwise copy constructor as the initialization of verb need not result in a function call.
1
2
3
4
5
6
7
8
9
class Word {
  public:
    Word( const char* );
    ~Word() { delete [] str; }
    // ...
  private:
    int cnt;
    char *str;
};
  • But, if the class word defined as follows, then it exhibits memberwise copy constructor & result in a function call because string declares explicit copy constructor.
1
2
3
4
5
6
7
8
9
class Word {
  public:
    Word( const string& );
    ~Word();
    // ...
  private:
    int cnt;
    string str;
};
  • In this case, the compiler needs to synthesize a copy constructor as follows in order to invoke the copy constructor of the member class string object:
1
2
3
4
5
6
// A synthesized copy constructor
inline Word::Word( const Word& wd )
{
  str.string::string( wd.str );
  cnt = wd.cnt;
}

Not: Bitwise Copy Semantics..!

When bitwise copy semantics not exhibited by a class? There are four instances:

  1. When the class contains a member object of a class for which a copy constructor exists (either explicitly declared by the class designer, as in the case of the previous string class, or synthesized by
    the compiler, as in the case of class Word)
  2. When the class derived from a base class for which a copy constructor exists (again, either explicitly
    declared or synthesized)
  3. When the class declares one or more virtual functions
  4. When the class derived from an inheritance chain in which one or more virtual base classes exist

In instances 1 & 2, the implementation needs to insert invocations of the member or base class copy constructors inside the synthesized copy constructor.

Other Ways: Can Copy Constructor Be Invoked

1
2
3
4
5
  X x0;
  X x1( x0 );
  X x2 = x0;
  X x3 = x( x0 );
  // ...
  • All these statements transform into the invocation of the copy constructor.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
X x0;
X x1;
X x2;
X x3;
// compiler inserted invocations
// of copy constructor for X
x1.X::X( x0 );
x2.X::X( x0 );
x3.X::X( x0 );
// ...