Reputation: 25928
I have a lambda that will occasionally cause an access violation when I try to erase an object from a std::vector
. I pass a copy of the object to be deleted to the lambda instead of an iterator because the iterator may not point to the correct object come execution time.
Is there a better way to setup a lambda to remove a specific object from a vector? And what is the exact cause of the access violation here? Its difficult to debug as the local and auto variables are null/corrupted when I debug during this error.
... 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
});
}
Upvotes: 0
Views: 153
Reputation: 62583
You are not following the proper remove
idiom. It is simple:
vec.erase(std::remove_if(vec.begin(), vec.end(), elem), vec.end());
You do not need to subtract anything or do any custom branches.
Upvotes: 2
Reputation: 8238
std::remove return the end iterator of the range where all values equal to customLayout
were removed. It actually does not remove anything, it just changes elements positions so that "removed" elements are placed after end iterator of the new range. Nevertheless, state of "removed" elements is unspecified and referencing them may cause problems.
Then, in terms of STL end iterator points at the element next to the last element of your range, not the last element itself. That's why any manipulations with end iterator (it
in your case) are invalid.
The most probable error scenario is when customLayouts
does not contain elements equal to customLayout
. Then it
points to an element which never existed, and erase
attempts to destroy it.
If you want to erase
the last element of the new (shorter) range, you should write customLayouts.erase(it - 1);
.
Upvotes: 0