Module 10 — Summary¶
The essentials¶
- A class that owns a resource must take control of copying, or refuse to be copied, or own nothing. There is no fourth option; leaving the decision to the compiler produces a member-wise copy and, for an owning pointer, two owners of one resource.
- The compiler's copy is member-wise, and it is exactly right when every member manages its own
resource —
std::string,std::vector,std::unique_ptr. It is catastrophically wrong when a member is a raw owning pointer, and the failure (a double free) appears at destruction, in a different function from the copy that caused it. - The Rule of Three: destructor, copy constructor and copy assignment come as a set, because they are three views of the same decision about what the class owns.
- Assignment must be self-assignment safe. Guard with
if (this == &other) { return *this; }, or use copy-and-swap and remove the question entirely. Both copy and move assignment can be reached through an alias. - The Rule of Five adds move construction and move assignment. Moves transfer the resource instead of duplicating it, which is why returning a container is cheap and why the Rule of Zero is possible at all.
std::moveis a cast, not an action. It makes aT&&overload selectable. If no move overload is viable — none exists, or the object isconst— a copy happens, silently.- A moved-from object is valid but unspecified: destroyable and assignable, not readable. The standard does not promise it is empty, even when your implementation leaves it empty.
noexcepton move operations decides whether containers move or copy your type. Without it, astd::vectorgrowing will copy, and nothing will tell you. Assert it if you depend on it:static_assert(std::is_nothrow_move_constructible<T>::value, "…").- Declaring one special member changes which others the compiler generates. A destructor suppresses the moves; a move operation deletes the copies. Decide for the group, not one at a time.
- The Rule of Zero is the goal: own no resource directly, declare none of the five, and the entire bug class — double free, leak, self-assignment, silent copy — disappears rather than being handled.
- Memory bugs are found by measuring, not by reading. Count allocations against frees, or let a sanitizer name both stacks. This is the module's technique, and it stays with you.
The one-sentence version¶
Make each class own at most one thing, express that ownership in a member type that already handles it, and then write no special member functions at all — because the alternative is five functions you must keep correct forever.
Terms you must now be able to define¶
copy constructor · copy assignment · move constructor · move assignment ·
destructor · special member functions · Rule of Three · Rule of Five ·
Rule of Zero · shallow copy · deep copy · double free · self-assignment ·
copy-and-swap · lvalue · rvalue · rvalue reference · std::move ·
moved-from state · noexcept move · = delete · = default · copy elision ·
strong exception guarantee
All of them are defined in the glossary under this module.
Before you move on¶
- [ ] All core exercises attempted, with expected results checked — and the before/after counters written down, not just observed
- [ ] The lab builds with no warnings and passes its checklist, with all three stages kept
- [ ] The double free was reproduced on purpose, with its evidence preserved
- [ ] Quiz score ≥ 80%, and every miss explained
- [ ] At least one challenge problem attempted
- [ ] Skills checklist ticked, with the evidence for each item
- [ ] I can look at any class and say whether the compiler's generated copy is correct for it
Where this goes next¶
Module 11 — RAII and Smart Pointers is this module's answer made into library types. You have just proved, the hard way, that a class which owns a raw pointer needs five correct functions. Module 11 replaces the resource with a member whose type does the owning — and the five functions stop being your problem.
Delete this from your habits now: writing delete in a class that also has a copy constructor.
Every owning class you write from here on should either be Rule of Zero, or be justified in
writing down why it cannot be.
Further reading¶
- Effective C++ (3rd ed.), Scott Meyers — the items on copying, assignment, and the Rule of Three are the origin of this module's framing.
- Effective Modern C++, Scott Meyers — move semantics,
std::move,noexcept, and the move-versus-copy distinction at depth, and the source of thestd::move-on-consttrap. - A Tour of C++ (3rd ed.), Bjarne Stroustrup — how value semantics and resource ownership are presented to working programmers, and why the Rule of Zero is the recommended default.
- cppreference: rule of three/five/zero — the language-level statement of this module's subject, including the exact generation table.
See Further Reading for the full list, with what each source is good for and when to reach for it.