Skip to content

82 Advanced The Hundred

The Move That Copies

your move constructor is present, correct, and ignored

#include <iostream>
#include <vector>

struct Pixel {
    Pixel() = default;
    Pixel(const Pixel&) { std::cout << "copy\n"; }
    Pixel(Pixel&&) { std::cout << "move\n"; }
};

int main() {
    std::vector<Pixel> pixels;
    pixels.reserve(3);
    for (int i = 0; i < 3; ++i)
        pixels.emplace_back();

    std::cout << "-- growing past capacity --\n";
    pixels.emplace_back();   // relocates the three old elements... by move, surely?
}

Run it. How do the three old elements reach the new buffer?

Answer
-- growing past capacity --
copy
copy
copy

Every element is duplicated. The move constructor sits right there and never runs.

Why

Growing past capacity means transferring every element to a fresh buffer, and vector promises the strong exception guarantee: if anything throws mid-transfer, the vector is left exactly as it was. A throwing move would wreck that: half the elements gutted out of the old buffer, and no way back. So the transfer uses std::move_if_noexcept, which moves only when the move constructor is noexcept and otherwise copies. Yours isn't marked, so as far as vector is concerned it might throw — and every reallocation silently copies the whole vector. -Wall -Wextra say nothing (GCC 11.5, Clang 18); clang-tidy's performance-noexcept-move-constructor does. A move-only type still gets moved: with no copy to fall back on, the guarantee is quietly downgraded.

The fix

One keyword turns the three copy lines into move:

Pixel(Pixel&&) noexcept { std::cout << "move\n"; }

Better yet, Pixel(Pixel&&) = default; — a defaulted move is noexcept whenever the members' moves are, one more reason to prefer the rule of zero.

Takeaway: a move constructor without noexcept is a copy in disguise wherever the strong exception guarantee matters — mark your moves noexcept.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo — then add noexcept to the move constructor and run again.

Open in Compiler Explorer ↗ Quiz this entry