当键是虚拟继承中涉及的基类指针时,对 std::unordered_map 项的访问崩溃



以下内容适用于 g++,但在使用 MSVC 编译时崩溃。我不知道我的代码是否有未定义的行为或其他什么。最小示例:

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;
}

此代码的问题在于 lambda 正在捕获通过引用o的局部变量。当函数f1()返回时,o的作用域不再存在。所以你有一个悬而未决的参考!因此,当您调用 lambda 时,您会得到未定义的行为。两个版本的地图都会发生这种情况。

要解决此问题,您可以改为按值捕获:

o->f = [=]()
{
std::cout << uMap[o] << 'n'; 
};

在这里,指针由 lambda 复制,并且在函数返回后它将有效。

这不应该编译,因为std::function不能假设捕获变量的lambda。不知道为什么编译。

第二个问题在技术上是 UB,不应该在 lambda 中工作(RVO 使其可行(,您通过引用捕获o,一旦您将函数f1(),该引用在技术上就失效。由于RVO,它可能仍然存在,但这仍然被认为是UB。

编辑:离开范围后捕获变量的 lambda 会发生什么?它不应该像无法捕获的 lambda 那样是可访问的。

最新更新