41 Intermediate The Hundred
std::remove Removes Nothing
the removal that never happens
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> v{1, 2, 3, 2, 4};
std::remove(v.begin(), v.end(), 2); // delete every 2... right?
std::cout << "size: " << v.size() << '\n';
for (int x : v)
std::cout << x << ' ';
std::cout << '\n';
}
Run it. What does it print?
Answer
size: 5, then 1 3 4 2 4 (typical output, GCC on x86-64). All five elements are
still there — including a 2.
Why¶
std::remove sees the world through a pair of iterators — it has no idea a vector
sits behind them, so it couldn't resize the container even if it wanted to. All an
algorithm can do is shuffle values: it shifts every kept element toward the front and
returns an iterator to the new logical end. Everything between that iterator and
v.end() is leftover — valid but unspecified values per the standard; in practice
the old tail, which is where the stray 2 4 comes from. The size never changes, and
by discarding the return value the snippet throws away the one thing remove
actually produced. Don't expect help: g++ 11 compiles this warning-free even with
-Wall -Wextra. std::unique sets the exact same trap.
The fix¶
Feed the returned iterator straight into erase — the classic erase–remove idiom:
Since C++20 there's a one-liner that does both jobs: std::erase(v, 2);.
Takeaway: std::remove only computes what to keep — it takes erase (a container
member) to actually shrink; never call one without the other.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo