Intermediate Gotchas
The Value Built for a Failed Insert
the map keeps its old value after loading a new one
std::string load_value() {
std::cout << "loading value\n";
return "new";
}
int main() {
std::map<int, std::string> records{{1, "old"}};
records.emplace(1, load_value());
std::cout << "stored: " << records.at(1) << '\n';
}
Does load_value run when key 1 already exists?
Answer
The map declined the insert, but it could not uncall the value factory.
Why¶
C++ evaluates load_value() before entering map::emplace, so collision detection
cannot save that work. emplace then finds key 1 and keeps the old mapped value.
try_emplace(1, load_value()) has the same eager call: it can suppress construction in
the container, but it cannot undo a function expression that already ran. Establish that
the key is absent before invoking an expensive factory.
The fix¶
Takeaway: emplace may skip insertion, never evaluation of the arguments you passed
to it.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo