Plast interview

9. Smart ownership

In a low-latency matching engine, ownership mistakes can leak and degrade cache behavior over long uptimes. Smart pointers must minimize refcount traffic while preserving safety across threads. Consider the following bidirectional link design.

#include <memory>
struct Node { std::shared_ptr<Node> next; std::weak_ptr<Node> prev; };
int main(){
  auto a = std::make_shared<Node>();
  auto b = std::make_shared<Node>();
  a->next = b; b->prev = a;
}

Part 1.

Why is prev a std::weak_ptr here? What would happen to lifetime and memory if prev were a std::shared_ptr?

Part 2.

(1) What latency costs arise from shared_ptr atomic refcounts on contended cores?

(2) When prefer std::make_shared over constructing shared_ptr<T>(new T) here?

(3) Is shared_ptr from unique_ptr construction noexcept? What risk matters in HFT?

(4) How does weak_ptr::lock() synchronize with destruction? Any memory ordering guarantees?

(5) How can enable_shared_from_this help or harm lifetime in cyclic graphs?

Answer

Answer (Part 1)

Using std::shared_ptr for both next and prev creates a reference cycle; their reference counts never reach zero, leaking memory. A std::weak_ptr breaks the cycle, allowing b (and then a) to be reclaimed deterministically once the strong owners drop, avoiding long-lived leaks in a daemon.

Answer (Part 2)

(1) Each increment/decrement is an atomic RMW causing cross-core cache traffic and potential stalls. Under contention, refcount thrash hurts tail latency via invalidations.

(2) std::make_shared performs a single allocation for object+control block, improving locality and exception safety. shared_ptr<T>(new T) uses two allocations and can leak on exceptions if misused.

(3) Constructing shared_ptr from unique_ptr may allocate a control block and can throw; it is not noexcept. If it throws, unique_ptr prevents leaks, but throws are catastrophic in hot paths.

(4) weak_ptr::lock() atomically checks/bumps the strong count so the object won’t be destroyed while held. It does not synchronize user data; separate memory ordering or locks are required for payload consistency.

(5) enable_shared_from_this yields shared_ptr aliases without creating a second control block, avoiding double-ownership bugs. Misuse can extend lifetimes unexpectedly or contribute to cycles when combined with other shared_ptr links.