Skip to content

60 Intermediate The Hundred

std::move Moves Nothing

the move that never happened

#include <iostream>
#include <string>
#include <utility>

int main() {
    std::string first = "a message long enough to defeat the small-string optimization";
    const std::string second = "a message long enough to defeat the small-string optimization";

    std::string a = std::move(first);
    std::string b = std::move(second);   // both buffers stolen... right?

    std::cout << "first  after move: \"" << first << "\"\n";
    std::cout << "second after move: \"" << second << "\"\n";
}

Run it. What's left in the two strings?

Answer

first comes out empty (typically). second comes out untouched — every character still there, because it was quietly copied, not moved.

Why

std::move never moves anything — it is just a static_cast to rvalue reference with a persuasive name, and the cast carries const along with it. That makes its argument eligible for a move; whether one actually happens is decided afterwards, by ordinary overload resolution between the move and copy constructors. std::move(second) yields a const std::string&&, which the move constructor string(string&&) cannot bind to — but the copy constructor string(const string&) can, so the compiler falls back to it. Silently: -Wall -Wextra says nothing (GCC 11). The non-const first genuinely moves, and libstdc++ leaves it empty — but the standard only promises a "valid but unspecified" state, so treat the emptiness as typical, not guaranteed.

The fix

A local you intend to move from must not be const — being moved from is a modification:

std::string second = "...";   // non-const: now std::move can actually deliver

The veto reaches inside classes too, but more narrowly: a const data member is itself copied during move construction (its sibling members still move), and it deletes move and copy assignment outright — a compile error there, not a silent copy.

Takeaway: std::move is a request, not a command — const vetoes it, and the veto is a silent copy.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry