Move Semantics and Zero-Copy
Move semantics let C++ transfer ownership of a large object's underlying data by stealing a pointer instead of copying every byte, which is the difference between a constant-time handoff and an expensive duplication.
Prerequisites: STL Container Performance
Before C++11, returning a large std::vector from a function, or passing one into a container, meant copying every element, allocate new memory, copy each byte, then destroy the original. For a vector of a million order-book updates, that's a real, measurable cost paid every time ownership needed to change hands, even though the data itself never actually needed to move in memory.
Move semantics fixed this by giving C++ a second way to transfer an object: instead of copying the contents, steal the internal pointer, size, and capacity from the source object and leave the source in an empty, valid-but-unspecified state. The new object now owns exactly the same block of memory the old one did, nothing was duplicated, only the ownership record changed. This is the "zero-copy" idea: the underlying bytes never move, only who's responsible for them.
A copy duplicates data; a move duplicates a pointer. For a std::vector<double> holding a million elements, a copy is a million-element memcpy, genuinely work, while a move is three pointer/integer assignments, regardless of how large the vector is.
What actually happens underneath
Worked example
std::vector<double> loadPrices(int n) {
std::vector<double> prices(n);
// ... fill with a million prices ...
return prices; // moved out, not copied
}
std::vector<double> book = loadPrices(1'000'000); // move construction
std::vector<double> backup = book; // copy, book is still needed
std::vector<double> archived = std::move(book); // explicit move, book is now empty
Returning prices from loadPrices triggers a move (compilers do this automatically for local variables returned by value), so no million-element copy happens at the function boundary. backup = book is a real copy because book is still a named variable the program plans to use again, the compiler can't safely steal from it. std::move(book) is the programmer explicitly saying "I'm done with book, you can steal its buffer", after that line, book is guaranteed to be in a valid but unspecified state (for std::vector, empty), and using it for anything but reassignment is a bug.
What this means in practice
Move semantics are why modern C++ containers can be passed around, returned from functions, and stored in other containers without the copy-everything tax that made pre-C++11 code defensively pass everything by reference. In a trading system, this matters most for large market-data structures, an order book snapshot, a batch of parsed ticks, where a copy at the wrong point in a hot path can add microseconds a competitor's move-based code doesn't pay.
The same idea generalizes past std::vector. Any type that manages a resource, a unique_ptr's owned memory, a file handle, a socket, can define its own move constructor, and the standard library types you already use (std::string, std::map, std::function) all do. That's why swapping a pre-C++11 codebase's return-by-value functions for return-by-value functions in modern C++ often speeds things up with no source change at all: the compiler was already free to move instead of copy, it just needed a move constructor to exist for the type in question.
Using an object after std::move-ing it is a classic bug, not a compile error, the moved-from object is still a legal object (usually empty), so the code compiles and runs, but silently operates on the wrong data. std::move does not itself move anything; it only casts the object to an rvalue reference, making it eligible to be moved by whatever receives it. If nothing actually consumes that rvalue, no move happens at all.
Discussion
💡 Discussion rules
- Ask and answer about this concept. Off-topic gets removed.
- No homework dumps. Show what you tried first.
- Corrections are welcome. Cite a source when you claim an error.
Loading discussion…
Related concepts
Practice in interviews
Further reading
- Meyers, Effective Modern C++ (items 23-30)