Skip to content

Intermediate Gotchas

The Counter That Split in Two

copying the callback quietly forks its history

std::function<int()> make_counter() {
  return [count = 0]() mutable { return ++count; };
}

int main() {
  auto first = make_counter();
  auto second = first;

  std::cout << first() << ' ' << second() << '\n';
  std::cout << first() << ' ' << second() << '\n';
}

Run it. Does second continue where first left off?

Answer
1 1
2 2

Each callback owns a separate counter.

Why

std::function has value semantics: copying it copies its stored callable. The mutable lambda's count is part of that callable object, so the copy starts with the same value but changes independently afterwards. GCC emits no warning under -Wall -Wextra.

The fix

Make the state explicitly shared when copies must observe one counter:

auto count = std::make_shared<int>(0);
return [count] { return ++*count; };

Takeaway: copying a std::function copies the closure and all of its value-captured state.

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

Open in Compiler Explorer ↗ Quiz this entry