16. Noexcept Moves
In a bursty market, container growth during message bursts must not degrade latency. Standard containers choose relocation strategies based on exception guarantees of element moves. Proper noexcept usage can eliminate expensive copies and enable tighter codegen in hot paths.
#include <vector>
struct Msg { Msg()=default; Msg(const Msg&)=default; Msg(Msg&&) {/*expensive*/} };
int main() {
std::vector<Msg> q;
for (int i=0;i<3;i++) q.emplace_back();
}
Part 1.
On vector growth, which operation will std::vector<Msg> use to relocate elements, and why? How would you change Msg to ensure the fastest relocation strategy under reallocation while preserving strong exception safety?
Part 2.
(1) When should move operations be noexcept, and how do containers exploit that?
(2) What happens if a noexcept function throws at runtime in production?
(3) Is noexcept part of a function type since C++17? ABI implications?
(4) How to conditionally declare noexcept based on member moves?
(5) Does noexcept affect codegen, inlining, and unwind tables on Linux?
Answer
Answer (Part 1)
std::vector prefers copying if a move might throw to preserve strong exception safety; your Msg(Msg&&) is not noexcept, so reallocation will copy. Declare the move constructor noexcept (e.g., Msg(Msg&&) noexcept = default;) so the vector relocates by moving, reducing latency and allocations while maintaining guarantees.
Answer (Part 2)
(1) Mark moves noexcept whenever they cannot throw; defaulted moves inherit members’ guarantees. Containers then use moves during reallocation instead of copies, minimizing cost.
(2) Throwing from a noexcept function calls std::terminate. In HFT, this is fail-fast; ensure no-throw or handle internally before termination.
(3) Since C++17, exception specifications are part of the function type. It affects overload resolution and symbol mangling, not calling convention.
(4) Use noexcept(std::is_nothrow_move_constructible_v<Member> && ...) or noexcept(noexcept(Member(std::declval<Member&&>()))). Prefer = default so the compiler deduces noexcept from members automatically.
(5) noexcept enables nounwind paths and more aggressive inlining/code motion. Unwind tables typically remain unless build flags alter EH/unwind generation.