Лучший способ удалить память для объектов из вектора - PullRequest
0 голосов
/ 23 сентября 2018

У меня есть вектор, который содержит объекты, расположенные в куче.Я хочу удалить некоторые элементы из вектора.Какой самый лучший способ удалить элемент из вектора и удалить его.

Один из способов опробован в следующем коде:

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 голосов
/ 23 сентября 2018

Ваш цикл в порядке, поскольку он удаляет и delete 'объекты (назначение nullptr не требуется).Но остальная часть вашего кода подвержена утечкам памяти.Если push_back() бросает, вы теряете объект, который вы только что new 'ред.И вы не delete 'объекты, которые все еще находятся в векторе после окончания вашего цикла.

Какой лучший способ удалить элемент из вектора и удалить его

Опция best - вообще не использовать необработанные указатели.Сохраняйте фактические экземпляры объектов непосредственно в векторе, и пусть вектор уничтожит их для вас, когда вы удаляете их, и когда сам вектор разрушается, когда он выходит из области видимости:

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;
}
0 голосов
/ 23 сентября 2018

лучший способ - использовать unique_ptr или (при необходимости) shared_ptr.В этом случае вы можете использовать стандартные идиомы 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;
}
...