Intuition The one core idea
A C++ class is a bundle of smaller members, and each member already knows how to copy, move, and clean itself up. If you build your class only out of members that manage themselves, the compiler writes all the "housekeeping" functions for you — correctly, for free — and you write zero.
This page is the ground floor . The parent note assumes you already know what a "class", a "member", a "pointer", "copy vs move", a "destructor", and "RAII" are. If any of those words feels fuzzy, read here first — every one is built from nothing.
A class is a blueprint that glues several smaller pieces of data together into one named thing. Each piece inside is called a member .
Picture a box with labelled slots. The box is the object (a thing built from the class blueprint); each slot holds one member .
Every rule on the parent page ("does the compiler write copy for me?") is really the question "do all the slots in this box already know how to handle themselves?" So we must first see the box as a collection of slots.
Members the individual data pieces stored inside an object.
Some slots hold a plain value (a number). Some slots hold a handle to a resource — memory grabbed from the operating system, an open file, a network socket. A value is self-contained. A resource lives elsewhere , and the slot only holds a ticket pointing to it.
A resource is something outside the object that must be explicitly acquired and later released — heap memory, a file, a lock. If you forget to release it, it leaks.
Definition Value type vs. handle
A value type (like int, double) is its own data. Copy the bits, you copy everything.
A handle (like a raw pointer int*) is only a reference to data that lives somewhere else.
Why the topic needs this: the whole Rule of Zero hinges on the difference. Copying a value slot is trivially safe; copying a handle slot is where all the danger lives.
A pointer , written int* ("pointer to int"), is a variable whose value is the address of some other data. Read *p as "the thing p points at".
new and delete
new int[n] asks the operating system for a block big enough for n integers and hands back its address (a pointer).
delete[] p gives that block back . Do it once — no more, no less.
Common mistake The double-free, in one picture
If two pointers hold the same address and both run delete[], the block is returned twice. The second return is a crash-class bug called a double-free . This single hazard is the reason the parent's "Step 2" breaks.
Pointer int* p a variable holding the address of an int living elsewhere.
delete[] p run twice on the same addressa double-free — undefined behaviour / crash.
This is the heart of the vocabulary. Suppose a box A holds a resource and we want a box B.
A copy makes B an independent duplicate : it acquires its own resource and fills it with the same contents. Afterwards A is untouched, and destroying one does not harm the other. This is called a deep copy when a resource is involved.
A move transfers A's resource to B and leaves A empty (but still safe to destroy). Nothing is duplicated — the ticket is simply handed over. This is fast because no new resource is acquired.
two operations exist
Copy answers "I need two independent things." Move answers "I'm done with the original; just give its guts to the new one." Move is cheap; copy can be expensive. C++ lets the compiler pick move when the source is about to disappear anyway.
Deep copy B gets its own resource holding the same contents; A unchanged.
Move A's resource is handed to B; A is left empty but destructible.
Every class secretly needs answers to these questions. If you don't write them, the compiler writes a default. These are the special member functions .
Definition The Big Five (+1)
For a class T:
Destructor ~T() — "how do I clean myself up?"
Copy constructor T(const T&) — "build me as a duplicate of that one."
Copy assignment T& operator=(const T&) — "make me a duplicate of that one (I already exist)."
Move constructor T(T&&) — "build me by stealing that one's guts."
Move assignment T& operator=(T&&) — "steal that one's guts (I already exist)."
Default constructor T() — "build me empty." (related but separate)
Decoding the notation, symbol by symbol:
~T() — the tilde ~ marks the destructor. Read "the un-maker of T".
const T& — a reference (&) to an existing T we promise not to change (const). Used for copy: we read the source without touching it.
T&& — a double ampersand marks an rvalue reference : a reference to something the compiler knows is temporary / about to die . This is the signal "you may safely steal from me" — the trigger for a move. (Deeper dive: Move semantics and rvalue references .)
~T()the destructor — cleanup code run when the object dies.
const T&a read-only reference to an existing object (used by copy).
T&&an rvalue reference — a handle to a temporary that may be safely stolen from (used by move).
RAII (Resource Acquisition Is Initialization) is the pattern where a resource is grabbed in the constructor and released in the destructor — automatically, when the object goes out of scope. See RAII — Resource Acquisition Is Initialization .
An RAII wrapper is a small class whose whole job is to hold one resource and know its five behaviours. The standard library ships several:
std::string, std::vector — own heap memory; deep-copy, cheap-move, auto-free.
std::unique_ptr — sole owner of one heap object; move-only.
std::shared_ptr — shared owner; copy = share.
Intuition Why RAII closes the loop
If your box's slots are all RAII wrappers (or plain values), then the compiler's memberwise generation just chains together already-correct behaviours. The whole class becomes correct without you writing a single special function — that is the Rule of Zero. It also makes the older Rule of Three and Rule of Five unnecessary in the common case.
RAII acquire in constructor, release in destructor — cleanup happens automatically at scope exit.
Why RAII members give Rule of Zero their own five functions are already correct, so memberwise generation is correct.
RAII self managing members
Read it bottom-up: the box-of-slots idea leads to the value/resource split; resources need pointers, which create the double-free danger; that danger is exactly what the Big Five must tame; RAII members tame it for you; and that is the Rule of Zero.
Test yourself — cover the right side and answer before revealing.
An object vs. a class a class is the blueprint; an object is one box built from it.
A member one data slot stored inside an object.
Value type vs. handle a value is its data; a handle only points at data living elsewhere.
What int* p stores the address of an int, not the int itself.
What delete[] p must never do run twice on the same address (double-free).
Deep copy duplicate the pointed-to data so the two objects share nothing mutable.
Move hand the resource over and leave the source empty-but-destructible.
The Big Five destructor, copy-ctor, copy-assign, move-ctor, move-assign.
Meaning of ~T() the destructor, run at end of the object's life.
Meaning of const T& read-only reference to an existing object (copy source).
Meaning of T&& rvalue reference — a temporary you may steal from (move source).
"Memberwise" generation the compiler's default copies/moves/destroys each member using that member's own function.
RAII acquire in the constructor, release in the destructor, automatically.
Why RAII members give you Rule of Zero each member is already correct, so the compiler-generated whole is correct too.