从共享指针向量中删除元素时内存损坏

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