Part of my program does something like this:
#include <unordered_set>
#include <unordered_map>
std::unordered_map<std::string, int> G{{"1", 10}};
int m(const std::string& i, std::unordered_set<std::string>& v) {
v.erase(i);
return G.at(i);
}
int main() {
std::unordered_set<std::string> v {"1"};
const std::string& remove_this = *v.begin();
return m(remove_this, v);
}
The program should be portable between linux and windows. When compiled with g++, the program runs well and returns 10, as expected. However, when compiled with VS 2017, the programs aborts, throwing an std::out_of_range. With most trivial effort of debugging, I see that i
in function m
is destroyed before the call to G.at
. (both without optimizations)
To my understanding, the const reference to v.begin()
should expire until m
returns (the g++ case). But it MSVC obviously didn't agree with that.
Is this undefined behavior or implementation defined? When, indeed, does an argument passed by const reference expire then?
The argument i
lives until m
ends. However, the object that i
references disappears after v.erase(i)
, leaving i
as a dangling reference. G.at(i)
then reads from the dangling reference causing undefined behavior.