C++ for trading: RAII, moves and what belongs on the hot path
SYS · Chapter 212 min readAsked at Hudson River Trading, Jump, Citadel Securities, Optiver
After this lesson you should be able to
- Explain RAII and why it is the foundation of safe C++.
- Distinguish copy from move and say when each happens.
- List what must not appear on a latency-critical path.
C++ is used on trading paths because it gives deterministic control over memory and timing with no runtime pauses. The language features that matter are the ones supporting that: deterministic destruction, value semantics, and the ability to say exactly what happens and when.
Definition 2.1
RAII
Resource acquisition is initialisation — Tie a resource to an object’s lifetime: acquire in the constructor, release in the destructor. Because destructors run deterministically when scope is left — including when an exception unwinds — there is no way to forget the release and no garbage collector deciding when it happens. This is the single most important idea in the language, and it is why unique_ptr, lock_guard and vector all follow the same pattern.
Proposition 2.2
Copy against move
A copy duplicates the resource; a move transfers ownership and leaves the source empty. Moves happen for temporaries and for anything explicitly std::moved, and they turn an copy of a container into an pointer swap.
Holds when
- Returning a local by value is free — the compiler elides the copy entirely.
std::movedoes not move anything; it is a cast that permits a move.- A moved-from object is valid but unspecified — you may destroy or assign to it, not read it.
| Avoid | Why | Instead |
|---|---|---|
new / malloc | May lock, may fault, unbounded latency | Preallocate; use a pool |
std::map | Node-based, a cache miss per level | vector or a flat map |
| Virtual dispatch | An indirect branch and no inlining | Templates, or a tagged union |
| Exceptions on the path | The throw path is very slow | Return codes for expected failures |
| Logging to a file | Syscall, possible blocking | Lock-free queue to another thread |
std::shared_ptr copies | Atomic refcount on every copy | Pass by reference; unique_ptr for ownership |
new in the middle of a tick handler costs a hundred times a branch and can block on the allocator’s lock; a syscall is another order beyond that. Hot-path code allocates nothing and calls nothing that might sleep.Why allocation is the cardinal sin. A call to new may take a lock in the allocator, may search a free list, may request memory from the kernel, and may trigger a page fault when the memory is first touched. Each of those is rare and none is bounded, so the mean cost looks fine and the tail is terrible — which is exactly the shape of failure a trading system cannot tolerate. Preallocating converts an unbounded worst case into a known one, and that predictability is worth more than the average nanoseconds saved.
The rest of this lesson is in Premium
You have read the opening. 10 more sections follow, including 4 worked examples and 3 quick checks.
Nothing is charged for 7 days, and you can cancel before then. Or read Complexity: reading it off, and deriving it in full, free.