Copy Constructor

When I run this code,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
using namespace std;

// declare a class
class Wall {
   private:
    double length;
    double height;

   public:

    // parameterized constructor
    Wall(double len, double hgt) {
        // initialize private variables
        length = len;
        height = hgt;
    }

    // copy constructor with a Wall object as parameter
    Wall(Wall &obj) {
        // initialize private variables
        length = obj.length;
        height = obj.height;
    }
    double calculateArea() {
        return length * height;
    }
};

int main() {

    // create an object of Wall class
    Wall wall1(10.5, 8.6);

    // print area of wall1
    cout << "Area of Wall 1: " << wall1.calculateArea() << endl;

    // copy contents of wall1 to another object wall2
    Wall wall2 = wall1;

    // print area of wall2
    cout << "Area of Wall 2: " << wall2.calculateArea() << endl;

    return 0;
}


I get:

1
2
Area of Wall 1: 90.3
Area of Wall 2: 90.3


However, if I comment out the copy constructor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
using namespace std;

// declare a class
class Wall {
   private:
    double length;
    double height;

   public:

    // parameterized constructor
    Wall(double len, double hgt) {
        // initialize private variables
        length = len;
        height = hgt;
    }

    // copy constructor with a Wall object as parameter
//    Wall(Wall &obj) {
//        // initialize private variables
//        length = obj.length;
//        height = obj.height;
//    }
    double calculateArea() {
        return length * height;
    }
};

int main() {

    // create an object of Wall class
    Wall wall1(10.5, 8.6);

    // print area of wall1
    cout << "Area of Wall 1: " << wall1.calculateArea() << endl;

    // copy contents of wall1 to another object wall2
    Wall wall2 = wall1;

    // print area of wall2
    cout << "Area of Wall 2: " << wall2.calculateArea() << endl;

    return 0;
}


I still get
1
2
Area of Wall 1: 90.3
Area of Wall 2: 90.3


Why would I ever even need to use a copy constructor other than what the compiler offers?
Last edited on
For example,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class A{
public:
    int *a;

    A(int value){
        this->a = new int(value);
    }
    ~A(){
        delete this->a;
    }
    A(const A &other){
        this->a = new int(*other.a);
    }
};

class B{
public:
    int *b;

    B(int value){
        this->b = new int(value);
    }
    ~B(){
        delete this->b;
    }
};

int main(){
    {
        A x(42);
        {
            A y(x);
        }
        std::cout << *x.a << std::endl;
    }
    //Everything OK up to this point.
    {
        B x(42);
        {
            B y(x);
        }
        //Oops! Both x.b and y.b were pointing to the same int. Now that y has
        //been destructed, x.b points to an invalid address, so the next line
        //will trigger undefined behavior.
        std::cout << *x.b << std::endl;
    }
}

In general, copy constructors are useful whenever you have classes that own resources (memory, system objects, etc.).
The members can be non-trivial. For example a pointer to "owned" memory. The implicit implementation does "shallow copy", which is almost always a huge mistake.

There is guideline, "Rule of Three": https://en.cppreference.com/w/cpp/language/rule_of_three


Note:
1
2
3
4
5
    Wall(double len, double hgt) {
        // initialize private variables
        length = len;
        height = hgt;
    }

The comment above is a lie. The body of the constructor does not initialize anything. It performs copy assignments.

If you want to initialize members, then you have to use member initializer list:
1
2
3
4
Wall(double len, double hgt)
 : length{len}, height{hgt}
{
}

I wish I'd learned C++ back in the day. I started coding in '83 and never really got past pascal.

@helios - you laid it out sensibly and it sticks. Much appreciated for that.

@keskiverto - You answered my bigger, unasked question: Isn't a Copy Ctor just a parameterized Ctor that makes "copies" of whatever to sel member vars? I may not be saying that the right way, so I hope you catch my drift.

Isn't a Copy Ctor just a parameterized Ctor that makes "copies" of whatever to sel member vars?
That would be what a trivial copy constructor does, such as the default one, or the one you wrote in your example above. It just literally copies the values of the members from one object to another.
What a copy constructor should do is create a copy of the state of an object such that the new object has semantics that make sense in the program.
For example, consider this:
1
2
3
4
5
String a;
a = "hello";
String b = a;
b = "goodbye";
std::cout << a;
Should the output be "hello", or "goodbye"? Either option is valid. There's different ways to implement the copy constructor to get one behavior or the other.
What a copy constructor should do is create a copy of the state of an object such that the new object has semantics that make sense in the program.


Thank you.
Topic archived. No new replies allowed.