来自 Lambda 的访问冲突偶尔会出现

Access Violation from Lambda occasionally exhibits itself

本文关键字:偶尔 访问冲突 Lambda 来自      更新时间:2023-10-16

我有一个lambda,当我尝试从std::vector中删除对象时,它偶尔会导致访问冲突。我将要删除的对象的副本传递给 lambda 而不是迭代器,因为迭代器可能不会在执行时间指向正确的对象。

有没有更好的方法来设置 lambda 以从向量中删除特定对象?这里访问违规的确切原因是什么?很难调试,因为在此错误期间调试时,局部变量和自动变量为空/损坏。

... std::vector<CustomLayout> customLayouts; // private class member variable
void App::loadCustomLayouts() {
    CustomLayout customLayout;
    // ... create HWND
    onMessage(WM_RBUTTONDOWN, [customLayout, this]() {
        auto it = std::remove(customLayouts.begin(), customLayouts.end(), customLayout);
        customLayouts.erase(it); // occasionally causes access violation
    });
}

您没有遵循正确的remove习语。很简单:

vec.erase(std::remove_if(vec.begin(), vec.end(), elem), vec.end());

您无需减去任何内容或执行任何自定义分支。

std::remove 返回删除所有等于 customLayout 的值的范围的结束迭代器。它实际上不会删除任何内容,它只是更改元素位置,以便将"删除"的元素放置在新范围的结束迭代器之后。但是,"已删除"元素的状态是未指定的,引用它们可能会导致问题。

然后,就 STL 而言,结束迭代器指向范围最后一个元素旁边的元素,而不是最后一个元素本身。这就是为什么任何使用结束迭代器的操作(在您的情况下it)都是无效的。

最可能的错误情况是当customLayouts不包含等于 customLayout 的元素时。然后it指向一个从未存在过的元素,erase试图摧毁它。

如果要erase新(较短)范围的最后一个元素,则应编写customLayouts.erase(it - 1);