Why C++ for quants
Pricing engines, risk systems, and execution gateways live or die on two things: predictable performance and deterministic resource handling. C++ gives you both because it exposes the machine model directly: you control whether an object lives on the stack or the heap, whether it is copied or shared, and exactly when its memory and other resources are released. The discipline that makes all of this safe is RAII — Resource Acquisition Is Initialization.
Value vs reference semantics
In C++ a variable of type double is a double; it is not a handle pointing somewhere else. This is value semantics. When you pass a value, you copy it unless you ask otherwise.
#include <iostream>
struct Quote { double bid; double ask; };
void widenCopy(Quote q) { q.ask += 0.01; } // edits a copy
void widenRef(Quote& q) { q.ask += 0.01; } // edits the original
int main() {
Quote eurusd{1.0810, 1.0812};
widenCopy(eurusd);
std::cout << eurusd.ask << "\n"; // 1.0812 unchanged
widenRef(eurusd);
std::cout << eurusd.ask << "\n"; // 1.0813 changed
return 0;
}
A reference (Quote&) is an alias for an existing object. Pass large objects by const reference to avoid copies while guaranteeing you will not mutate them: void price(const Quote& q).
Stack vs heap
Objects declared as local variables live on the stack: allocation is a pointer bump, deallocation is automatic when the scope exits, and access is cache-friendly. Objects created with new live on the heap: allocation is slower, lifetime is manual, and you must eventually delete them. In hot quant code you prefer the stack; you reach for the heap only when an object must outlive its scope or its size is decided at runtime.
RAII: tie resources to object lifetime
RAII means a resource (memory, a file handle, a market-data subscription, a lock) is acquired in a constructor and released in the destructor. Because C++ guarantees destructors run when an object leaves scope — even via an exception — RAII makes leaks structurally impossible.
#include <iostream>
class PriceBuffer {
double* data_;
std::size_t n_;
public:
explicit PriceBuffer(std::size_t n) : data_(new double[n]), n_(n) {
std::cout << "acquire " << n_ << " slots\n";
}
~PriceBuffer() { // runs automatically
delete[] data_;
std::cout << "release\n";
}
double& operator[](std::size_t i) { return data_[i]; }
std::size_t size() const { return n_; }
};
void useBuffer() {
PriceBuffer pb(3);
pb[0] = 100.5;
// no manual delete; ~PriceBuffer runs at scope exit
}
The constructor acquires; the destructor releases. If useBuffer threw after pb[0] = 100.5, the destructor would still fire during stack unwinding.