- References
- Function Overloading
- Default Function Arguments
- Inline Function
- Dynamic Memory Allocation
- Placement New
- nullptr
- Namespaces
- Type Aliases
- Enum classes
- constexpr
- static_assert
- mutable Keyword
- auto Keyword
- Smart Pointers
- Basics of Classes
- Constructors
- Destructors
- Operator Overloading
- Copy Semantics
- Move Semantics
- Composition, RAII & Ownership
- Inheritance
- Polymorphism
- Abstraction
- Encapsulation
- Template
- Static Memory
- Friend Function
- this Pointer
- Function Pointer
- Lambdas and Callback Management
- Union
Composition, RAII & Ownership

These three concepts form the backbone of robust C++ architecture.
- Composition ("Has-a"): Instead of inheriting from classes ("Is-a"), you build complex objects by combining smaller, simpler objects. A
Carhas anEngine, it is not anEngine. - RAII (Resource Acquisition Is Initialization): The "Golden Rule" of C++. Resources (Memory, Locks, Files) are acquired in the Constructor and released in the Destructor. This ties resource management to the Scope, guaranteeing cleanup.
- Ownership: Defines who is responsible for the lifetime of a resource. "If I own it, I delete it."
Syntax & Usage
1. Composition (Building Blocks)
Composition allows you to swap parts easily and keeps dependencies clear.
class PWM {
public:
void set(int duty) { /* ... */ }
};
class Encoder {
public:
int read() { /* ... */ }
};
// Composition: MotorController "Has-a" PWM and "Has-a" Encoder
class MotorController {
PWM pwm_driver; // Sub-component 1
Encoder enc_driver; // Sub-component 2
public:
void set_speed(int speed) {
int current = enc_driver.read(); // Delegate work
pwm_driver.set(speed);
}
};2. RAII (The Scope Guard)
The most common embedded use case is managing interrupts or mutexes.
class ScopedIntLock {
public:
ScopedIntLock() { __disable_irq(); } // Acquire
~ScopedIntLock() { __enable_irq(); } // Release
};
void critical_function() {
ScopedIntLock lock; // Interrupts disabled HERE
// ... do critical work ...
if (error) return; // Safe! Destructor re-enables interrupts automatically.
} // Destructor runs here naturally.Ownership Model
| Ownership Type | Concept | C++ Tool |
|---|---|---|
| Owner | "I control this life. When I die, it dies." | std::unique_ptr or Member Variable. |
| Shared Owner | "We keep this alive as long as one of us needs it." | std::shared_ptr. |
| Observer | "I just look at it. I hope it's still there." | Raw Pointer (T*) or Reference (T&). |
Relevance in Embedded/Firmware
1. Composition over Inheritance
Embedded hierarchies can get messy ("Is a SPI driver a Stream? Is it a Bus?").
Composition is cleaner. A Sensor class shouldn't inherit from I2C. It should contain a pointer/reference to an I2C driver. This allows you to easily swap the I2C driver for a SPI driver without rewriting the Sensor class.
2. Leak-Free Error Handling
In C, if an error occurs in the middle of a function, you must remember to free() memory or unlock() mutexes before every return.
With RAII, you just return. The compiler inserts the cleanup code for you (Stack Unwinding), making firmware crash-proof.
3. Clear Lifetimes
By using Composition and RAII, you avoid "dangling pointers" where a driver tries to access a hardware object that has already been de-initialized. If the parent object (Robot) dies, its children (Motors) are destroyed automatically and in the correct order.
Common Pitfalls (Practical Tips)
| Pitfall | Details |
|---|---|
| ❌ Deep Inheritance | Avoid creating 5-layer deep class hierarchies (Driver -> Serial -> UART -> STM32_UART). It increases code size (v-tables) and makes debugging a nightmare. Prefer Composition. |
| ❌ Raw Pointers as Owners | Never use a raw pointer (
|
| ❌ Circular Dependency | If Object A owns B, and Object B owns A (via shared_ptr), they will keep each other alive forever (Memory Leak). Use weak_ptr or raw references to break the cycle. |
| ✅ Dependency Injection | Pass the "Sub-components" into the Constructor rather than creating them inside.
|
Concept understood? Let's apply and learn for real