Как я могу освободить указатель вектора? - PullRequest
5 голосов
/ 14 сентября 2010

Как я могу освободить память в векторе указателя? Вот код:

class A
{
    private:
        int x,y,z;
    public:
        A(param1, param2, param3)
        {
            x=param1;
            y=param2;
            z=param3;
        }
        ~A()
        {
            //prompts an alertbox, warning me about the successful call of the destructor;
        }
};

...
vector<A*> list;
list.push_back(new A(1,2,3));

list.erase(list.begin()+index);//SHOULD delete the object from the memory;
list.clear();

Я обнаружил, что .erase() не освобождает память и не вызывает деструктор; Я пытался использовать delete для каждой записи списка с итерацией, но вылетает после одной итерации. Уже проверено, была ли запись в списке уже NULL, чтобы избежать ошибок. Я что-то пропустил? Кроме того, я должен использовать только STL, не нужно Boost.

Ответы [ 6 ]

8 голосов
/ 14 сентября 2010

list.erase освободит память для ее элементов-членов (и вызовет их деструкторы, если они существуют); это не вызовет delete на них.

Повышение shared_ptr было бы очевидным способом сделать это. Если вы не хотите использовать это, вы либо напишите свой собственный класс интеллектуальных указателей, либо переберите list и вызовете delete для каждого указателя перед вызовом erase. Вы можете сделать это аккуратно с помощью чего-то вроде:

void my_delete(A *p)
{
    delete p;
}

...

std::for_each(list.begin(), list.end(), my_delete);
4 голосов
/ 14 сентября 2010
for( std::vector<A*>::iterator i = list.begin(), endI = list.end(); i != endI; ++i)
{
   delete *i;
}
list.clear();

или, используя новые лямбда-функции

std::for_each( list.begin(), list.end(), []( A* element) { delete element; });
list.clear();
3 голосов
/ 14 сентября 2010

erase стирает только то, что находится в векторе (указатели), не делая ничего о том, на что они могут указывать.

Если вы хотите, чтобы точка была удалена, вам нужно обработать это самостоятельно.

Мой совет - избегать обработки любого самостоятельно и рассмотреть возможность использования Boost ptr_vector.

2 голосов
/ 14 сентября 2010

После уничтожения контейнер STL уничтожит содержащиеся в нем объекты. Если эти объекты являются указателями, то они уничтожат указатели. Для обнаженных тупых указателей это не приведет к удалению объектов, на которые они указывают . Вот почему обычно лучше использовать для этого умные указатели. Умные указатели будут удалять объекты, на которые они ссылаются при удалении; std::shared_ptr отслеживает копирование указателей и сколько существует ссылок на данный объект, и удалит объект, только когда последний указатель умрет. Это всегда хороший первый кандидат при поиске подходящего умного указателя. Ваш контейнер будет объявлен так: std::vector< std::shared_ptr<A> >

Однако ваш компилятор / стандартная библиотека может не поставляться с std::shared_ptr, что является функцией следующего стандарта C ++, который обычно ожидается в следующем году. Тем не менее, он может поставляться с std::tr1::shared_ptr, который является функцией TR1 с 2003 года. (Если все остальное не помогло, boost имеет boost_shared_ptr, но вы уже исключили повышение.)

Вы можете вручную управлять динамически размещенными объектами в контейнерах STL, но это обременительно и подвержено ошибкам. Например, вы должны предотвратить преждевременный возврат функций (до ручной очистки) с помощью операторов или исключений return, а также следить за операциями копирования в контейнерах. (В противном случае два контейнера будут иметь указатели, ссылающиеся на одни и те же объекты, которые вы можете попытаться уничтожить дважды.)
Управление ресурсами вручную - это PITA, оно подвержено ошибкам и его лучше избегать.

1 голос
/ 14 сентября 2010

Код, который вы разместили, не является допустимым C ++.Кроме того, стирание не удаляет выделенные вами объекты, а только стирает содержимое вектора, которые в вашем случае являются указателями.Фактические объекты, которые вы выделили, не удаляются.Вот правильный способ сделать то, что вы хотите:

#include <vector>
#include <algorithm>

class A
{
    int x,y,z;

public:
    A (int param1, int param2, int param3) :
        x (param1), y (param2), z (param3)
    {
    }
};

struct Deleter
{
    template <typename T>
    void operator () (T *obj) const
    {
        delete obj;
    }
};

int
main ()
{
    std::vector<A*> list;

    list.push_back (new A (1, 2, 3));
    list.push_back (new A (4, 5, 6));
    list.push_back (new A (7, 8, 9));

    std::for_each (list.begin (), list.end (), Deleter ());
    list.clear ();
}

Вы также можете взглянуть на библиотеку Boost Ptr Container , которая решает эту проблему безопасным и повторно используемым способом.В C ++ 0x есть шаблонный класс std :: unique_ptr, который поддерживает подвижную семантику и может использоваться с контейнерами и алгоритмами STL для автоматической очистки памяти.

0 голосов
/ 14 сентября 2010
for(size_t i = 0; i < list.size(); ++i)
{
    delete list[i];
}

list.clear();

Если вы делаете что-то подобное и ваш код дает сбой, отправьте точный код и информацию о сбое.

...