从向量中删除对象的最佳方法

时间:2018-09-23 06:00:58

标签: c++ vector heap-memory

我有一个向量,其中包含在堆上分配的对象。我想从向量中删除一些元素。这是从向量中删除元素并将其删除的最佳方法。

下面的代码尝试了一种方法:

class MyObj
{
    bool rem;
public:
    MyObj(bool r) : rem(r) { cout << "MyObj" << endl; }
    ~MyObj() { cout << "~MyObj" << endl; }

    bool shouldRemove() const noexcept { return rem; }
};


int main()
{
    vector<MyObj*> objs;
    objs.push_back(new MyObj(false));
    objs.push_back(new MyObj(true));
    objs.push_back(new MyObj(false));
    objs.push_back(new MyObj(true));

    auto itr =  objs.begin();
    while (itr != objs.end())
    {
        if ((*itr)->shouldRemove())
        {
            delete *itr;
            *itr = nullptr;

            itr = objs.erase(itr);
        }
        else
            ++itr;
    }

    // size will be two
    cout << "objs.size() :" << objs.size() << endl;

    return 0;
}

2 个答案:

答案 0 :(得分:6)

就删除和delete对象而言,您的循环很好(不需要nullptr分配)。但是您的其余代码容易出现内存泄漏。如果抛出push_back(),则会泄漏刚刚new处理过的对象。而且,循环结束后,您不会delete处理向量中仍存在的对象。

  

从矢量中删除元素并将其删除的最佳方法是

最佳选项是完全不使用原始指针。将实际的对象实例直接存储在矢量中,让矢量在删除实例时以及在矢量对象超出范围时被销毁时为您破坏实例:

int main() {
    std::vector<MyObj> objs;

    objs.emplace_back(false);
    objs.emplace_back(true);
    objs.emplace_back(false);
    objs.emplace_back(true);

    auto itr = objs.begin();
    while (itr != objs.end()) {
        if (itr->shouldRemove())
            itr = objs.erase(itr);
        else
            ++itr;
    }

    /* alternatively:
    objs.erase(
        std::remove_if(objs.begin(), objs.end(),
            [](auto &o){ return o.shouldRemove(); }),   
        objs.end()
    );
    */

    // size will be two
    std::cout << "objs.size() :" << objs.size() << std::endl;

    return 0;
}

否则,如果您需要存储指向动态分配对象的指针,请至少使用智能指针来管理它们:

int main() {
    std::vector<std::unique_ptr<MyObj>> objs;

    objs.push_back(std::unique_ptr<MyObj>(new MyObj(false)));
    objs.push_back(std::unique_ptr<MyObj>(new MyObj(true)));
    objs.push_back(std::unique_ptr<MyObj>(new MyObj(false)));
    objs.push_back(std::unique_ptr<MyObj>(new MyObj(true)));

    /* alternatively, if you are using C++14 or later
    objs.push_back(std::make_unique<MyObj>(false));
    objs.push_back(std::make_unique_ptr<MyObj>(true));
    objs.push_back(std::make_unique<MyObj>(false));
    objs.push_back(std::make_unique<MyObj>(true));
    */

    auto itr = objs.begin();
    while (itr != objs.end()) {
        if ((*itr)->shouldRemove())
            itr = objs.erase(itr);
        else
            ++itr;
    }

    /* alternatively:
    objs.erase(
        std::remove_if(objs.begin(), objs.end(),
            [](auto &o){ return o->shouldRemove(); }),  
        objs.end()
    );
    */

    // size will be two
    std::cout << "objs.size() :" << objs.size() << std::endl;

    return 0;
}

答案 1 :(得分:1)

最好的方法是使用unique_ptr或(如果需要)shared_ptr。 在这种情况下,您可以使用remove-erase idiom之类的标准c ++习惯用法。另外一个好处-没有内存泄漏。

#include <vector>
#include <iostream>
#include <memory>
#include <algorithm>
using namespace std;

class MyObj
{
    bool rem;
public:
    MyObj(bool r) : rem(r) { cout << "MyObj" << endl; }
    ~MyObj() { cout << "~MyObj" << endl; }

    bool shouldRemove() const noexcept { return rem; }
};


int main()
{
    vector<unique_ptr<MyObj>> objs;
    objs.emplace_back(make_unique<MyObj>(false));
    objs.emplace_back(make_unique<MyObj>(true));
    objs.emplace_back(make_unique<MyObj>(false));
    objs.emplace_back(make_unique<MyObj>(true));

    objs.erase(remove_if(objs.begin(), objs.end(), [](unique_ptr<MyObj> const & item){ return item->shouldRemove(); }),
               objs.end());

    // size will be two
    cout << "objs.size() :" << objs.size() << endl;

    return 0;
}