


AAYou’re joining a fintech risk engine written in modern C++ that processes millions of transactions per day under strict latency SLOs and regulatory audit requirements. A single memory bug (leak, double-free, use-after-free) can cause process crashes, corrupted risk decisions, or hard-to-reproduce incidents that block releases.
Explain your experience with C++ memory management by walking through how you would design, implement, and debug memory ownership in a performance-sensitive service.
Address the following:
std::unique_ptr, std::shared_ptr, and std::weak_ptr. When is shared_ptr a code smell? How do you avoid cycles?Assume the interviewer expects implementation-level depth: object layout and allocation, move/copy semantics, destructor behavior, container ownership patterns, and trade-offs between safety and performance. Use a concrete example (e.g., a graph of risk rules, an in-memory cache, or a request pipeline) to demonstrate how you’d apply these principles.
Stack allocation ties lifetime to scope and is typically faster with deterministic destruction. Heap allocation is used when lifetime must outlive a scope, size is large/variable, or polymorphism/indirection is needed, but it introduces ownership complexity and fragmentation risks.
std::string a = "stack-owned"; // destroyed at scope end
auto p = std::make_unique<Foo>(); // heap object, owned by unique_ptr
RAII (Resource Acquisition Is Initialization) binds resource lifetime to object lifetime so cleanup happens in destructors even during exceptions. Exception safety levels (basic/strong/nothrow) describe how much state remains valid after an exception, and RAII is the foundation for achieving them.
std::lock_guard<std::mutex> lk(mu); // unlocks on all exits
std::vector<int> v; v.push_back(x); // strong guarantee for many ops
unique_ptr models exclusive ownership and enables move-only APIs that make lifetimes obvious. shared_ptr models shared ownership via reference counting but can hide costs and create cycles; weak_ptr breaks cycles by holding a non-owning reference.
auto u = std::make_unique<Node>();
auto s = std::make_shared<Node>();
std::weak_ptr<Node> w = s; // observe without extending lifetime
Leaks happen when ownership is unclear or cleanup paths are missed; double-free occurs when multiple owners think they own the same raw pointer; use-after-free occurs when a non-owning pointer outlives the owned object. These are often introduced by mixing raw pointers with manual new/delete or by storing references into containers that reallocate.
int* p = new int(7);
delete p;
// ... later
*p = 9; // use-after-free (UB)
AddressSanitizer catches out-of-bounds and use-after-free with low friction in CI; UBSan flags undefined behavior; Valgrind can detect leaks and invalid accesses but is slower. Heap profilers (tcmalloc/jeprof, heaptrack) help attribute memory growth to allocation sites and object types.