Undefined Behavior in C++
This chapter doesn't re-derive c3-4's own UB deep dive — everything there still applies, unchanged. This is only what's genuinely new to C++ specifically.
Everything From c3-4 Still Applies
Signed overflow, out-of-bounds access, dangling pointers, use-after-free, double-free, strict aliasing, excessive shifts, data races — every category c3-4 catalogued applies unchanged, since C++ inherits C's entire UB model at the language-core level.
Object Slicing
A genuinely new-to-C++ trap: assigning a derived-class object to a base-class object by value — not through a pointer or reference — "slices off" the derived part entirely, leaving only the base portion. Not technically undefined behavior in the strict sense (copying just the base part is well-defined), but almost always a serious logic bug, since cpp1-7's own virtual dispatch is lost entirely.
This is exactly what cpp2-6's own "catch by reference to avoid slicing" tip was pointing toward — now fully explained.
Pure Virtual Function Called From a Constructor
A genuinely real, subtle trap: calling a virtual function from a base class's own constructor does not dispatch to a derived override, even if the object being constructed is ultimately a derived type. Calling a pure virtual function this way is genuinely undefined behavior, not merely surprising.
Why Construction Order Causes This
During a base class's own constructor, the object's hidden vtable pointer is set to point at the base class's vtable — not the derived one. It's updated to point at successively more-derived vtables as each level of construction completes, finishing only once the most-derived constructor runs. Calling a virtual function mid-construction sees whatever vtable is currently set, never the final one.
Uninitialized Member Variables
C++ class members of built-in types (int, pointers, etc.) are not automatically zero-initialized unless explicitly done so in the constructor — a real, common gotcha, especially coming from a language with different defaults. Rust simply doesn't allow reading an uninitialized variable at all — a compile error, closing this exact class of bug structurally.
| Concept | C (c3-4) | C++-specific addition | Rust |
|---|---|---|---|
| Core UB categories | signed overflow, OOB, dangling pointers, etc. | inherited unchanged | structurally prevented in safe code |
| Slicing a polymorphic object | n/a — no inheritance | a real logic bug, virtual dispatch silently lost | n/a — no equivalent value-slicing concept |
| Uninitialized member read | UB — garbage value | UB — garbage value, same as C | compile error — cannot read before initializing |
cpp2-6's own advice, now fully justified: catch exceptions by reference, and generally pass/return any polymorphic object by pointer or reference, never by value — value semantics and virtual dispatch simply don't mix safely.
Coding Challenges
Reproduce this chapter's own Shape/Circle slicing example: assign a Circle to a plain Shape variable by value, call area() on the sliced Shape, and confirm it calls Shape's own implementation rather than Circle's.
📄 View solutionFix Challenge 1 so that calling area() correctly dispatches to Circle's own implementation, without changing anything about how the Circle object itself is constructed.
📄 View solutionExplain precisely why calling a virtual function from a base class's own constructor doesn't dispatch to a derived override, tying your answer to exactly when the object's vtable pointer is updated during construction.
📄 View solutionChapter 5 Quick Reference
- Every UB category from
c3-4applies unchanged in C++ — nothing re-derived here - Object slicing — assigning a derived object to a base BY VALUE loses the derived part and virtual dispatch, silently
- Calling a virtual (especially pure virtual) function from a base constructor doesn't see the derived override — the vtable pointer isn't finalized yet
- C++ built-in-type members are not zero-initialized by default — unlike Rust, which refuses to compile a read before initialization
- Never pass/return polymorphic objects by value — always by pointer or reference
- Next chapter: the capstone — a modern C++ project combining everything from this entire track