Plast interview

6. RAII handles

In a low-latency matching engine, a preallocated ring stores per-order metadata. An RAII handle wraps a small resource to avoid leaks, but incorrect ownership can inject stalls or UB.

struct Slot { int* p; ~Slot() noexcept { delete p; } };
void g() {
    Slot a{new int(1)};
    Slot b = a;
}

Part 1.

What goes wrong at runtime and how would you redesign Slot to safely manage ownership in a hot path without extra overhead?

Part 2.

(1) Should Slot's destructor be noexcept? Explain the impact if it throws.

(2) When is move preferable to copy for owning RAII, and why?

(3) Any benefit to using unique_ptr<int> inside Slot with custom deleter?

(4) How does nothrow move construction influence vector<Slot> reallocation behavior?

(5) What lifetime pitfalls arise with temporaries and references bound to Slot subobjects?

Answer

Answer (Part 1)

Copying a into b duplicates the raw pointer, so both destructors delete the same allocation: double-delete UB. Make Slot move-only (delete copy ctor/assign; provide noexcept move that steals the pointer and nulls the source) or store a std::unique_ptr<int> with an appropriate deleter. Keep the destructor non-throwing to avoid termination during unwinding and to preserve container guarantees in hot paths.

Answer (Part 2)

(1) Yes. Destructors are implicitly noexcept; throwing during unwinding calls std::terminate, disrupting latency and correctness.

(2) Owning types should not be copyable; copying would duplicate ownership. Move transfers ownership cheaply without extra allocations or refcounts.

(3) Yes: it encodes unique ownership and correct moves by default. Custom deleter is in the type, often inlined with zero overhead.

(4) If std::is_nothrow_move_constructible is true, vector<Slot> prefers moves on reallocation. Otherwise it may copy to preserve strong guarantees.

(5) References/pointers into a moved-from Slot can dangle after move or destruction. Binding to temporaries risks use-after-destroy when scope ends.