10. Own or Observe
In a low-latency handler, ownership mistakes silently leak memory and destabilize long-lived processes. Heap traffic also adds jitter and cache misses. Model ownership explicitly and keep lifetimes predictable.
struct Msg { int id; };
void use(const Msg&);
int process() {
Msg* m = new Msg{1};
if (m->id < 0) return -1;
use(*m);
delete m;
}
Part 1.
Identify the ownership flaw and refactor for leak-free, exception-safe semantics with minimal latency. Show a corrected approach and justify it.
Part 2.
(1) Prefer stack allocation or unique_ptr for small Msg in hot loops? Why?
(2) How do you transfer ownership through APIs? unique_ptr by value or raw pointer?
(3) How do you model non-owning access? Reference vs pointer semantics and nullability?
(4) What are size and ABI effects of unique_ptr custom deleters?
(5) Why must destructors be noexcept, and how does that affect unwinding in hot paths?
Answer
Answer (Part 1)
Early return leaks the heap-allocated Msg; manual new/delete is brittle under control-flow or exceptions. Prefer automatic storage: int process(){ Msg m{1}; if(m.id<0) return -1; use(m); } for zero allocation and implicit cleanup. If heap lifetime is required, return/accept std::unique_ptr<Msg> by value; construction and destruction are exception-safe and explicit.
Answer (Part 2)
(1) Prefer stack: no allocation latency, better cache locality, fewer indirections. Use unique_ptr only when lifetime must outlive scope or transfer.
(2) Transfer with std::unique_ptr<T> by value; ownership moves to the callee. Raw owning pointers obscure intent and lifetime.
(3) Use T&/const T& for non-null, non-owning access; T* for optional. Document lifetimes; never persist beyond owner.
(4) Custom deleter changes the type; non-empty deleters increase unique_ptr size, affecting ABI and cache. Prefer empty, stateless deleters.
(5) Destructors should be noexcept to avoid std::terminate during unwinding and enable optimizations. RAII cleanup must not throw in hot code.