Review a C++ ownership sketch with raw allocations and redesign its interfaces around RAII and appropriately restrictive smart pointers. Discuss factory ownership, copying and moving, exception safety, non-owning access, shared lifetimes, cycles, and polymorphic destruction.
# Repair Unsafe C++ Ownership with Smart Pointers
Review this ownership sketch:
```cpp
class Engine {
public:
void start();
};
class Controller {
Engine* engine_;
public:
Controller() : engine_(new Engine()) {}
Engine* engine() const { return engine_; }
};
Controller* make_controller() {
return new Controller();
}
```
Identify the lifetime and ownership defects. Redesign the interfaces using RAII and the most restrictive appropriate smart-pointer types. Discuss copying, moving, exception safety, non-owning access, and what would change if an `Engine` had to be shared by several controllers.
### Clarifying Questions to Ask
- Is a controller the sole owner of its engine in the normal design?
- Must controllers be copyable, movable, or polymorphic?
- Can an engine outlive every controller that uses it?
- Does the factory transfer ownership to its caller?
### What a Strong Answer Covers
- Explicit ownership for both allocated objects
- Correct use of `unique_ptr`, `shared_ptr`, or a non-owning reference based on stated lifetime
- Rule-of-zero or deliberate copy/move semantics
- Exception-safe construction and awareness of reference cycles
### Follow-up Questions
1. When is a raw pointer acceptable in the redesigned API?
2. Why is replacing every raw pointer with `shared_ptr` not a safe default?
3. How would you represent an optional, non-owning observer whose target may disappear?
4. What happens to object layout and destruction through a polymorphic base?
Quick Answer: Review a C++ ownership sketch with raw allocations and redesign its interfaces around RAII and appropriately restrictive smart pointers. Discuss factory ownership, copying and moving, exception safety, non-owning access, shared lifetimes, cycles, and polymorphic destruction.
Identify the lifetime and ownership defects. Redesign the interfaces using RAII and the most restrictive appropriate smart-pointer types. Discuss copying, moving, exception safety, non-owning access, and what would change if an Engine had to be shared by several controllers.
Clarifying Questions to Ask Guidance
Is a controller the sole owner of its engine in the normal design?
Must controllers be copyable, movable, or polymorphic?
Can an engine outlive every controller that uses it?
Does the factory transfer ownership to its caller?
What a Strong Answer Covers Guidance
Explicit ownership for both allocated objects
Correct use of
unique_ptr
,
shared_ptr
, or a non-owning reference based on stated lifetime
Rule-of-zero or deliberate copy/move semantics
Exception-safe construction and awareness of reference cycles
Follow-up Questions Guidance
When is a raw pointer acceptable in the redesigned API?
Why is replacing every raw pointer with
shared_ptr
not a safe default?
How would you represent an optional, non-owning observer whose target may disappear?
What happens to object layout and destruction through a polymorphic base?