5.2.8 · D1C++ Programming

Foundations — Copy constructor and copy assignment — Rule of Three

2,664 words12 min readBack to topic

This page assumes you have seen nothing. Before you touch the Rule of Three itself, we will define — from absolute zero — every piece of notation and every idea the parent note leans on: what a variable in memory is, what an object is, what an address is, what a pointer is, what the heap is, what new and delete do, and what an object owning a resource even means. Each idea is anchored to a picture and earns its keep.


1. Memory, variables, and the street of numbered boxes

Figure — Copy constructor and copy assignment — Rule of Three

The picture: a row of boxes. Box number 1000 holds the character 'h', box 1001 holds 'i', box 1002 holds a special "end of text" marker written '\0' (a byte whose value is zero — called the null terminator). The number under a box (1000) is its address; the letter inside is its value. A variable is just a label stuck onto one of these boxes.

Why the topic needs this: the entire double-free bug is about two variables holding the same address. You cannot understand "same address" until you can see variables as labels on numbered boxes.


2. What an object is

Why the topic needs this: the parent note keeps saying "an object owns a resource", "two objects fight over one buffer", "the object dies". Every one of those sentences is really about a bundle of boxes — one of which is an arrow — and whether two such bundles point at the same borrowed run. Keep the picture: an object is a labelled group of boxes.


3. char and the string of boxes

Why +1 everywhere? The word "hi" is 2 letters but needs 3 boxes — the extra one for '\0'. That is exactly why the parent writes new char[len + 1]: len letters plus one terminator box. Miss the +1 and you write off the end of your street.


4. Pointers: an arrow that says "over there" (and the empty arrow)

Figure — Copy constructor and copy assignment — Rule of Three

The picture: a small box labelled data (the pointer) with an arrow reaching across to the "hi\0" run. The pointer's value is 1000 — the address of the first letter. To "follow the arrow" and reach the letters is called dereferencing.

Why the topic needs this: the compiler's automatic copy duplicates the arrow (the address), not the run of boxes. Two objects, two arrows, one buffer. Everything the parent calls "shallow copy" is this picture with two arrows.


5. The heap: borrowing boxes with new, returning them with delete

Figure — Copy constructor and copy assignment — Rule of Three

The picture: a "borrow counter" onto the heap. new[] slides a run of boxes across the counter to you (arrow returned). delete[] slides them back. Because heap boxes outlive the function that made them (unlike stack boxes), nobody frees them for you — the whole point of the Rule of Three is making sure every borrow is returned exactly once — never zero times (a memory leak, boxes never returned) and never twice (a double free, returning already-returned boxes, which crashes).

Why the topic needs this: "the resource an object owns" is a run of heap boxes from new[]. The destructor is just the promise "I will delete[] my boxes when I die."


6. Objects that own a resource

Why "own" is the key word: if two objects both believe they own the same run, both will try to delete[] it — double free (UB). The Rule of Three exists to guarantee one buffer, one owner by giving each copied object its own run (a deep copy). This idea of "resource freed automatically when the owner dies" is the seed of Destructors and RAII.


7. The three notations you'll read constantly


8. size_t and operator=


Prerequisite map

Memory as numbered boxes

Address is a house number

Variable is a label on boxes

Object is a bundle of boxes

Pointer is an arrow to a box

nullptr is an empty arrow

char star points at a run of letters

Heap is boxes you borrow

new borrows heap boxes

delete returns them once

Dangling pointer after free

Object owns a resource

Shallow copy copies the arrow

Deep copy copies the boxes

Two owners one buffer means double free

Double free is undefined behaviour

One owner one buffer is safe

Rule of Three

this and address-of and reference


Equipment checklist

Test yourself — you are ready for the parent note when every line reveals no surprise.

What is an address?
The permanent house-number of a box (byte) in memory.
What is a variable?
A name (label) glued to one or more memory boxes so you can read/write them by name.
What is an object?
A bundle of boxes that belong together under one name and type.
What two facts does every memory box carry?
Where it lives (address) and what's inside (value).
What is a pointer?
A variable whose value is an address — drawn as an arrow to another box.
What is nullptr?
The special "points nowhere" pointer value (address 0) — an empty arrow you must never dereference.
What is a dangling pointer?
An arrow still holding the address of boxes that have already been returned (freed).
What does char* hold?
The address of the first box of a run of characters.
Why does a 2-letter word need 3 boxes?
One extra box for the null terminator '\0' that marks the end.
What is the heap?
A pool of boxes you can borrow at any time for any lifetime, and must return yourself (unlike the automatic stack).
What does new char[n] give you?
An arrow (address) to a freshly borrowed run of n heap boxes.
What must new[] be paired with, and why?
delete[] — mismatched forms are undefined behaviour.
What is undefined behaviour?
A situation the language leaves totally unconstrained — crash, corruption, or silent "works for now"; the compiler assumes it never happens.
What is a memory leak?
Borrowed boxes never returned (delete never called).
What is a double free?
Returning the same boxes twice — undefined behaviour (a crash).
What does it mean for an object to own a resource?
It is responsible for returning that resource exactly once.
Shallow vs deep copy in one line each?
Shallow copies the arrow (shared buffer); deep copies the boxes (own buffer).
What does &other mean (value form)?
The address of other — an arrow to it.
What does const T& other mean?
A reference (alias) to other that you promise not to change.
What is this?
The address of the object the current method was called on.
What does this == &other test?
Whether I am the very same object I'm being asked to copy from (self-assignment).
Why is len a std::size_t?
It's a count/size, which can never be negative.