2008-11-11 1 views
7

Если у меня есть следующий код,Удаляет ли myVector.erase (myPtr) объект, на который указывает myPtr?

Foo *f = new Foo(); 
vector<Foo*> vect; 
vect.push_back(f); 
// do stuff 
vect.erase(f); 

ли я создать утечку памяти? Я так думаю, но слово erase дает ощущение, что оно удаляет его.

Написал это, мне интересно, не помешать ли указатель в STL-векторе. Как вы думаете?

ответ

8

Да, вы создали утечку памяти. std :: vector и другие контейнеры просто удаляют указатель, они не освободят память, на которую указывает указатель.

Нестандартно помещать указатель в стандартный контейнер библиотеки. Проблема, однако, заключается в том, что вам необходимо отслеживать удаление ее при ее удалении из контейнера. Лучше, но простой, способ сделать выше, чтобы использовать повышение :: shared_ptr:

{ 
    boost::shared_ptr<foo> f(new foo); 

    std::vector< boost::shared_ptr<foo> > v; 
    v.push_back(f); 
    v.erase(v.begin()); 
} /* if the last copy of foo goes out of scope, the memory is automatically freed */ 

Следующий стандарт C++ (так называемый C++ 1x и C++ 0x обычно) будет включать в себя std::shared_ptr. Там вы также сможете использовать std::unique_ptr<T>, который быстрее, так как он не позволяет копировать. Использование std::unique_ptr с контейнерами в C++ 0x аналогично библиотеке ptr_container в boost.

+0

Будьте очень осторожны, чтобы использовать boost :: shared_ptr, как указано в этом ответе, вместо auto_ptr. Контейнеры STL не могут использоваться вообще с auto_ptr (причина в том, что объяснение в этом комментарии немного длиннее). – Gorpik 2008-11-11 16:45:45

+0

Хорошо, я принимаю к сведению это. Благодаря ! – Barth 2008-11-12 07:30:39

1

Не обязательно указывать указатель на стандартный контейнер (однако, ошибка заключается в создании контейнера auto_ptr). Да, вам нужно явно удалить, чтобы освободить память, на которую указывают отдельные элементы, или вы можете использовать один из ускорений smart pointers.

4

Другой вариант - использовать Boost Pointer Containers. Они предназначены для того, чтобы делать именно то, что вы хотите.

2

В качестве альтернативы есть boost :: ptr_vector container.

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

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

Foo *f = new Foo(); 
boost::ptr_vector<Foo> vect; 
vect.push_back(f); 
// do stuff 
vect.erase(f); 
+0

Отличная ссылка, спасибо за это. Так получилось, что я провел последние несколько дней с рефакторингом структур данных контейнеров из-ptrs, boost :: косвенный_литератор был полезен, но эти контейнеры ptr_xxx были бы еще лучше, я думаю ... Может быть, мне нужно будет снова реорганизовать;) – Roel 2008-11-12 10:13:23

1

vector удаляет содержащиеся в нем данные. Поскольку ваш вектор содержит указатели, он удаляет указатели, а не данные, которые они могут или не могут указывать.

Это довольно общее правило на C++, что память освобождается там, где она была выделена. Вектор не выделял, на что указывают ваши указатели, поэтому он не должен отпускать его.

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

vector<Foo> vect; 
vect.push_back(Foo()); 
// do stuff 
vect.erase(f); 

Конечно, это предполагает, что Foo является копируемым, и что его конструктор копирования не слишком дорого, но это позволяет избежать утечек памяти, и вы не Не нужно забывать удалить объект Foo. Другим подходом было бы использование интеллектуальных указателей (таких как Boost's shared_ptr), но вам может не понадобиться семантика указателей вообще, и в этом случае простое решение является лучшим.

1

Контейнеры STL не освободят вашу память.Лучший совет - использовать интеллектуальные указатели, зная, что std :: auto_ptr не будет помещаться внутри контейнеров. Я бы рекомендовал boost :: shared_ptr, или если у вашего поставщика компилятора есть поддержка расширений TR1 (многие делают), вы можете использовать std :: tr1 :: shared_ptr.

Также обратите внимание, что вектор даже не освободит внутреннюю память, зарезервированную для указателя. std :: vector никогда не уменьшают даже при вызове clear(). Если вам нужно уменьшить размер вектора, вам придется прибегать к созданию другого вектора и свопинга содержимого.

2

Чтобы выяснить, почему указатель не удаляется, рассмотрим

std::vector<char const*> strings; 
strings.push_back("hello"); 
strings.push_back("world"); 
// .erase should not call delete, pointers are to literals 

std::vector<int*> arrays; 
strings.push_back(new int[10]); 
strings.push_back(new int[20]); 
// .erase should call delete[] instead of delete 

std::vector<unsigned char*> raw; 
strings.push_back(malloc(1000)); 
strings.push_back(malloc(2000)); 
// .erase should call free() instead of delete 

В общем, vector<T*>::erase не может угадать, как вы бы утилизировать T*.

 Смежные вопросы

  • Нет связанных вопросов^_^