The following works with g++, but crashes when compiled with MSVC. I don't know if my code has undefined behaviour or whatever. Minimal example:
class C1
{
};
// without virtual, it works.
// I need virtual because there is a C3 that inherits from C1,
// and then C4 that inherits from C2 and C3
class C2 : virtual public C1
{
public:
std::function<void()> f;
};
std::unordered_map<C1*, int> uMap;
//std::unordered_map<C2*, int> uMap; // doesn't crash
C2* f1()
{
C2* o = new C2;
o->f = [&]()
{
std::cout << uMap[o] << '\n'; // MSVC: 0xC0000005: Access violation reading location
};
return o;
}
int main()
{
auto o = f1();
o->f();
delete o;
}
C2* f1() { C2* o = new C2; o->f = [&]() { std::cout << uMap[o] << '\n'; // MSVC: 0xC0000005: Access violation reading location }; return o; }
The problem with this code is that the lambda is capturing a local variable o
by reference. When the function f1()
returns the scope of o
no longer exists. So you have a dangling reference! Therefore, when you invoke the lambda you get undefined behaviour. This happens with both versions of the map.
To get around the problem you can capture by value instead:
o->f = [=]()
{
std::cout << uMap[o] << '\n';
};
Here the pointer is copied by the lambda and it will be valid after the function returns.
This shouldn't compile as std::function
cannot assume lambdas that capture variables. Not sure why it compiles.
Second issue that is technically UB and shouldn't work (tho, RVO makes it workable) in lambda you capture o
by reference and that reference is technically invalidated once you leave the function f1()
. Due to RVO it might still remain but this is still considered UB.
Edit: also what happens to the lambda that captures variables after you leave the scope? It shouldn't be accessible unlike captureless lambdas.
User contributions licensed under CC BY-SA 3.0