Raffaele Rossi
Raffaele Rossi

Reputation: 3147

C++ understand copy constructor

There is something that I am not able to understand. Look at this kind of main:

class C {
 public:
  C() { cout << "C0 "; }
  C(const C&) { cout << "Cc"; }
};

class D {
 public:
  C c;
  D() { cout << "D0 "; }
  D(const D&) { cout << "Dd"; }
};

int main() {

  D x; cout << endl;
  D y(x); cout << endl;
  return 0;

}

//output is:
C0 D0
C0 Dd

I agree on the fact that D x gives C0 D0 as output because in class D there is a call to the default constructor of C and then the object D is created.

Also D y(x) is like D y = x where (like before) C is created (so output C0) and the the copy constructor is called. Why doesn't the Cc appear? If you consider this code:

class C {
 public:
  C() { cout << "C0 "; }
  C(const C&) { cout << "Cc"; }
};

class D {
 public:
  C c;
  D() { cout << "D0 "; }
};

int main() {

  D x; cout << endl;
  D y(x); cout << endl;
  return 0;

}

//output is:
C0 D0
Cc

Why now the output is Cc?

The code are equal except for the fact that there isn't a definition of the copy constructor on D. Saying that D y(x) is like D y = x I'd expect like before that C is created (calling default constructor so output C0) and then no text because D(const D&) is not defined.

Maybe I am misunderstanding copy constructors. How are they called in this case?

Upvotes: 2

Views: 869

Answers (3)

joeking
joeking

Reputation: 2106

In the first case your D Copy constructor needs to explicitly call the C copy constructor.

D(const D &d) :  c(d.c) 
{ cout << "Dd"; }

In the 2nd case, since you do not define a D copy-ctor, the compiler generates one for you.

To make this clearer, add an extra int to both C and D.

static int counter;
class C {
 public:
  int index;
  C() { index = ++counter; cout << "C0 "; }
  C(const C&) { index = c.counter; cout << "Cc"; }
};

class D {
 public:
  int dcounter;
  C c;
  D() { dcounter = ++counter; cout << "D0 "; }
  D(const D&) : dcounter(D.dcounter)
{ cout << "Dd"; }
};

Now, step thru with a debugger, or add more printfs(). When you do D y(x), you will see that the member c in y isn't copied from anything - just constructed.

Upvotes: 6

Remy Lebeau
Remy Lebeau

Reputation: 598434

Also D y(x) is like D y = x

It is not LIKE it, it IS EXACTLY it. The latter is just syntax sugar for the first.

where (like before) C is created (so output C0) and the the copy constructor is called

No, the C copy constructor is not called in that case. You did not define your D copy constructor to call the C copy constructor, so the c member is default-constructed instead, which is why you see C0, but since you did not actually copy c, you don't see Cc.

You are expecting the D copy constructor to automatically call the copy constructors of D's members, but that is simply NOT the case. You have to explicitly define that behavior yourself, eg:

D(const D &src) : c(src.c) { }

Why doesn't the Cc appear?

Because your C copy constructor is not called at all in your D y(x) example.

Upvotes: 3

Patrick87
Patrick87

Reputation: 28332

When you define a custom copy constructor, it does what you tell it to; you don't tell it to copy the c member, so it doesn't, hence C0. Indeed, if you were to a value in that c you'd see it's not even available in the newly copied member.

When you don't have a custom copy constructor, the default one that gets invoked invokes copy constructors for members it copies. In this case, you would see a value end up in the copied instance.

Upvotes: 3

Related Questions