Skip to content
Work Practice Products Coding interviews Machine learning coding Quant developer HFT course Blog Method Why me About Enquire Book a call

Blog · Quant careers

Low-latency C++ interview questions, and what a good answer sounds like

The developer round at a trading firm is rarely about a clever algorithm. It is twenty lines of C++ and a question about what the machine does with them. Here are twelve that come up, grouped by what they test.


Software engineers who interview at high-frequency trading firms and market makers usually expect a harder version of a standard coding interview. They get that, and then a second round that surprises them. The interviewer puts a short piece of C++ on the screen, agrees that its Big-O is fine, and asks why it is slow. Then what happens when a second thread touches it. Then how you would prove either answer.

Having been on both sides of these conversations as a quant developer, I find the same dozen ideas carry most of the weight. What follows is each question as it tends to be asked, the trap in it, and the shape of an answer that lands. Every one is covered in depth, with diagrams you step through and model answers, in the Quant developer HFT course.

Memory and the CPU

1. Both loops are O(n). Why is ours twice as slow?

The trap is to say "constant factors" and stop, or to say "cache misses" as a guess. The interviewer has told you the factor; they want the method. Compare one iteration of each loop: what memory it reads and in what order, whether it allocates or copies, whether its calls are direct and inlinable, whether its branches are predictable. Then say how you would check the benchmark itself. The lesson What Big-O leaves out builds that answer step by step.

2. Vector or linked list for a container you scan on every update?

A vector, and the reason is not complexity. Its elements are contiguous, so each 64-byte cache line fetched holds the next few elements and the hardware prefetcher runs ahead. A list's next address lives inside the current node, so every step waits for a load to return. Say when a list would still be right (stable iterators, splicing) and what you would use instead on a hot path. See Vector and list: where the data actually sits.

3. Eight threads increment one atomic counter and it gets slower. Why?

Each increment needs the counter's cache line in exclusive state on its core, so the line moves between cores on every write and the increments serialise on those transfers. Memory ordering does not change that. Per-thread counters on separate cache lines, summed when read, do. If the counters are already per thread but adjacent in memory, the answer is false sharing, and alignas(64) is the fix.

C++ that stays correct

4. What does std::move do?

Nothing at run time: it is a cast to an rvalue reference that makes the move constructor eligible. The follow-up is usually why a vector of your objects copies instead of moving when it grows. The answer is a move constructor without noexcept: the vector keeps its strong exception guarantee by copying unless moving cannot throw.

5. This function returns a string_view. Is it safe?

A view owns nothing, so it is safe only while what it points into lives and does not change. Returning a view of a temporary string compiles, because strings convert to views implicitly, and dangles at the end of the statement. Name the rule: views as parameters, owners as return values and members, unless the lifetime is obvious.

6. Is shared_ptr a problem on the order path?

Each copy is an atomic increment, each destruction an atomic decrement, on a count that several threads may touch; each object is an allocation; and the last owner, whoever it is, runs the destructor at an unpredictable moment. Ownership in an order manager is rarely shared, so the usual design is a pool owned by one component, references for synchronous use and handles with a generation check for anything that refers to an order later.

Threads

7. Which memory orders does a flag that publishes data need?

Release on the store, acquire on the load. The release keeps the data write from moving after the flag; the acquire keeps the data read from moving before it; together they make the data visible to the reader. Add that on x86 both compile to plain moves and only constrain the compiler, which is why code with the wrong ordering can pass every test on a laptop and fail on ARM.

8. Design the queue between the feed thread and the strategy thread.

One producer and one consumer, so a single-producer single-consumer ring: preallocated slots, a power-of-two capacity, the producer alone writing the tail, the consumer alone writing the head, release and acquire on the indices, the two indices on separate cache lines, and each side caching the other's index. The consumer spins on its own core rather than sleeping on a condition variable, because waking a thread goes through the kernel. The concurrency module steps through the ring as it fills and wraps.

The operating system and the network

9. The first few thousand messages after start-up are slow. Why?

First-touch page faults: Linux maps physical memory lazily, so the first write to each page of every pool and ring stops the thread while the kernel finds, zeroes and maps a page. Add cold caches and lazily resolved code. The fix is to pre-fault and lock memory at start-up and to warm the code paths with recorded traffic before the open.

10. Why is market data UDP multicast and order entry TCP?

Market data is one to many and loses value in milliseconds: multicast delivers each packet to every subscriber at once, and UDP never holds fresh data back behind a lost packet. Loss is handled with sequence numbers, redundant A and B feeds and recovery services. Orders are one to one and must arrive exactly once and in order, which TCP gives; on short dedicated links its cost in normal operation is small. Then mention TCP_NODELAY.

Measurement and trading systems

11. How fast is your system? Give me a number.

Give a distribution instead: p50, p99, p99.9 and the maximum of tick-to-trade, measured with the network card's hardware timestamps on the triggering packet and on the order, over a stated period. The mean hides the tail, and in trading the tail coincides with the busiest moments. Expect a follow-up on coordinated omission.

12. Design an order book for a market-by-order feed.

Start from the operations: adds, cancels and executions identified by order id, most of them near the best prices. A hash map from order id to a handle in a preallocated pool; price levels near the touch in an array indexed by ticks; an intrusive time-ordered queue per level; the best level tracked as an index; prices as integer ticks, never doubles. The full design is free to read in Designing an order book.

How to prepare

Read these as a list of mechanisms, not answers to memorise: the cache line, the coherence protocol, the allocator's slow path, the page fault, the context switch, the kernel's network stack. An interviewer can rephrase any question; they cannot get past a candidate who can explain the mechanism and say how to measure it. Practise out loud. A strong answer names the cost, the mechanism and the fix, then the measurement that would confirm it, in about a minute.

The Quant developer HFT course takes these topics in order across ten modules, with a drill at the end of each in which you answer real prompts and compare your answer with a strong one. Seven lessons are free to read in full, including the cost model and the order book.

Book the strategy hour — £250 What the hour covers →

Paid in full, in advance. No refunds. Full terms


Read next

All essays are on the blog. One problem a week, with the solution, if you subscribe.

LinkedIn X Facebook WhatsApp Telegram Email