从共享指针向量中删除元素时内存损坏
Memory corruption when removing elements from a vector of shared pointers
昨天我正在处理一个令人烦恼的错误,该错误涉及一个旨在从共享指针向量中删除元素的函数。这是有问题的代码:
template <typename T>
void flush(
std::vector<std::shared_ptr<T>>& offers
) {
std::vector<unsigned int> idxs;
for (unsigned int i = 0; i < offers.size(); i++) {
if (!offers[i]->is_available()) {
idxs.push_back(i);
}
}
for (unsigned int i : idxs) {
offers[i] = offers.back();
offers.pop_back();
}
}
偶尔,offers
向量的元素会损坏(即它们会指向垃圾数据)。我最终更改了上面的代码以使用更标准的擦除 - 删除习惯用法:
template <typename T>
void flush(
std::vector<std::shared_ptr<T>>& offers
) {
offers.erase(
std::remove_if(
offers.begin(),
offers.end(),
[](std::shared_ptr<T> offer) { return !offer->is_available(); }
),
offers.end()
);
}
现在我没有看到与以前相同的问题(无论如何这都更加优雅)。但是,我想了解为什么以前的代码不起作用时这会起作用。我怀疑它与向量中保留的错误元素有关,或者可能与指针的引用计数发生了一些奇怪的事情有关,但我希望能深入了解这里到底发生了什么。
只是发布一个快速答案,以便将其标记为已解决。问题是第二个循环:为了使算法工作,索引需要按降序排序;否则我们将访问越界数据。我相信以下行为应该正确:
template <typename T>
void flush(
std::vector<std::shared_ptr<T>>& offers
) {
std::vector<unsigned int> idxs;
for (int i = offers.size()-1; i >= 0; i--) {
if (!offers[i]->is_available()) {
idxs.push_back(i);
}
}
for (unsigned int i : idxs) {
offers[i] = offers.back();
offers.pop_back();
}
}
昨天我正在处理一个令人烦恼的错误,该错误涉及一个旨在从共享指针向量中删除元素的函数。这是有问题的代码:
template <typename T>
void flush(
std::vector<std::shared_ptr<T>>& offers
) {
std::vector<unsigned int> idxs;
for (unsigned int i = 0; i < offers.size(); i++) {
if (!offers[i]->is_available()) {
idxs.push_back(i);
}
}
for (unsigned int i : idxs) {
offers[i] = offers.back();
offers.pop_back();
}
}
偶尔,offers
向量的元素会损坏(即它们会指向垃圾数据)。我最终更改了上面的代码以使用更标准的擦除 - 删除习惯用法:
template <typename T>
void flush(
std::vector<std::shared_ptr<T>>& offers
) {
offers.erase(
std::remove_if(
offers.begin(),
offers.end(),
[](std::shared_ptr<T> offer) { return !offer->is_available(); }
),
offers.end()
);
}
现在我没有看到与以前相同的问题(无论如何这都更加优雅)。但是,我想了解为什么以前的代码不起作用时这会起作用。我怀疑它与向量中保留的错误元素有关,或者可能与指针的引用计数发生了一些奇怪的事情有关,但我希望能深入了解这里到底发生了什么。
只是发布一个快速答案,以便将其标记为已解决。问题是第二个循环:为了使算法工作,索引需要按降序排序;否则我们将访问越界数据。我相信以下行为应该正确:
template <typename T>
void flush(
std::vector<std::shared_ptr<T>>& offers
) {
std::vector<unsigned int> idxs;
for (int i = offers.size()-1; i >= 0; i--) {
if (!offers[i]->is_available()) {
idxs.push_back(i);
}
}
for (unsigned int i : idxs) {
offers[i] = offers.back();
offers.pop_back();
}
}