Tech News
← Back to articles

C++ std::move doesn't move anything: A deep dive into Value Categories

read original related products more articles

12/9/2025 42 min std::move doesn't move anything: A deep dive into Value Categories #cpp #performance #systems

The Problem: When “Optimization” Makes Things Slower

Let’s start with something that trips up even experienced developers. You write what looks like perfectly reasonable C++ code:

struct HeavyObject { std ::string data; HeavyObject ( HeavyObject && other ) : data ( std :: move (other.data)) {} HeavyObject ( const HeavyObject & other ) : data (other.data) {} HeavyObject ( const char* s ) : data (s) {} }; std :: vector < HeavyObject > createData () { std ::vector < HeavyObject > data; // ... populate data ... return data; } void processData () { auto result = createData (); }

This code works. It compiles. It runs. But depending on how you’ve implemented your types, it might be performing thousands of expensive copy operations instead of cheap moves without you realizing it.

Here’s what’s happening behind the scenes: When your std::vector needs to grow beyond its reserved capacity, it allocates new memory and moves all elements from the old memory to the new memory. But here’s the catch, if your move constructor isn’t marked with the noexcept keyword, the compiler won’t use it at all. Instead, it falls back to copying every single element.

Why? Because std::vector needs to maintain what’s called the “strong exception guarantee.” This is a fancy way of saying: if something goes wrong during reallocation, your original vector should be left completely untouched. If copies throw an exception during reallocation, no problem, the original vector is still intact. But if moves throw an exception, some elements might have already been moved, leaving your original vector in a corrupted state.

So the standard library plays it safe: if your move constructor might throw (because you didn’t mark it noexcept ), containers just copy everything instead. That “optimization” you thought you were getting? It’s not happening.

And here’s where things get interesting: std::move won’t magically fix this problem. In fact, if you use it incorrectly, you’ll make things worse. Let me show you why.

The Mechanics: What is std::move Really?

... continue reading