# Recap - Copy Constructors

## Motivation&#x20;

By default, when objects of user-defined types are copied, the compiler simply does a copy of all values of all member variables of that object.

Suppose a class has member variables which are pointers to memory dynamically allocated; when a copy of an object of this class is made, it copies the **memory address** stored by this pointer. This is known as a **shallow copy**.

This is problematic if the destructor of the class deletes the memory stored by these pointers, in an attempt to clean up after itself. This will cause a **double-free** memory error when both the original and copied object goes out of scope, as the destructor of the first object that is destructed invalidates the pointer copy held by the other object.

```cpp
struct Foo {
    int* value_ptr;  // A pointer as a member variable

    Foo(int value) {
        value_ptr = new int(value);  // Dynamically allocated `int` 
    }

    ~Foo() {
        delete value_ptr;  // Delete the value stored since we dynamically allocated it 
    }
};

int main() {
    Foo foo1(1);  // Create an instance of `Foo`
    Foo foo2 = foo1; // Create a copy based on `foo1`
}

/* Output:
      free(): double free detected in tcache 2
      signal: aborted (core dumped)
*/
```

## Copy Constructors&#x20;

### What is a Copy Constructor?&#x20;

The copy constructor is a special type of constructor that is called **when a new object is created from an existing object as a copy of the existing object**.&#x20;

The following cases fall into situations where the copy constructor is invoked:

* When an object of the class is returned by value&#x20;

```cpp
// The return type `Foo` is returning BY VALUE
// the variable created in line 4
Foo MakeFoo(int value) {
    Foo foo(value);
    return foo;
}
```

* When an object of the class is passed by value to a function as an argument&#x20;

```cpp
// The argument type `Foo` means that the argument 
// `some_foo` is copied from the instance that is 
// used to invoke this function.
void TakeFoo(Foo some_foo) {
    // ...
}
```

* When an object is constructed based on another object of the same class&#x20;

```cpp
int main() {
    Foo foo(1);
    // Constructing a new instance based on copying
    // the one above 
    Foo bar = foo;  
}
```

* When the compiler generates a temporary object&#x20;
  * We'll get into this *much* later.

### How do Copy Constructors help?&#x20;

The copy constructor is akin to a function, one whose body we can supply with logic to ensure **deep copies** of all dynamic member variables whenever it is invoked:

```cpp
struct Foo {
    // ...

    Foo(const Foo& other) {
        std::cout << "Invoking the copy constructor..." << std::endl;
        this.value_ptr = new int(*other.value_ptr);
    }
};
```

The copy constructor takes an object of the same class as a constant reference parameter, this will be the source object (i.e. the one being copied *from*) that we can use to write our custom copy code.

By default, the compiler would've done:

```cpp
this.value_ptr = other.value_ptr;
```

But we've now replaced that with:

```cpp
this.value_ptr = new int(*other.value_ptr);
```

Which ensures that the underlying value of `value_ptr` is copied, instead of the memory address of the one held by the original instance; therefore, the destructors of each instance then go on to free different memory addresses, and our predicament has been solved.&#x20;

## Copy Assignment Operator&#x20;

The copy assignment operator is a regular assignment operator (`operator=`) whose intention is to copy an existing object into an already initialised object of the same type:

```cpp
int main() {
    Foo first(1);
    Foo second(2);
    
    // Calls the copy assignment operator, this is
    // the same as "first.operator=(second);"
    first = second;  
}
```

Do not be mistaken, the above code **will not** invoke the copy constructor as it is not constructing a new instance from an existing value, but assigning an existing value to another.

As before, this also performs a shallow copy of the `Foo` objects and with it the same issues we were just covering before.&#x20;

Similar to defining custom copy code with the Copy Constructor, we can override this behaviour with the **Copy Assignment operator**.

```cpp
struct Foo {
    // ...

    Foo& operator=(const Foo& other) {
        std::cout << "Invoking the assignment operator..." << std::endl;
        delete value_ptr;
        this->value_ptr = new int(*other.value_ptr);
        return *this;
    }
};
```

The syntax for this is a little more nuanced – it returns a reference to either a new `Foo` object, or you can return the current one with its values properly copied if you're able to re-use it.&#x20;

The main difference is that we also have to free the memory held by `value_ptr` of the instance that is to be copied **to**, since it was already initialised to some other value prior to being assigned a new one.&#x20;

{% hint style="info" %}
**Copy constructor** is called when a new object is created from an existing object, as a copy of the existing object. And **assignment operator** is called when an already initialized object is assigned a new value from another existing object.
{% endhint %}
