Каков правильный способ освободить std:: вектор указателей на C++?
Я искал StackOverflow, но не смог найти ответ на этот вопрос.
Предположим, у меня есть std::vector<Day *> vector_day
- то есть-вектор указателей на Day
"объект". Теперь Я!--4--> до vector_day
многие элементы:
vector_day.push_back(new Day(12));
vector_day.push_back(new Day(99));
vector_day.push_back(new Day(71));
...
теперь в какой-то момент мне больше не нужно vector_day
. Как правильно освободить память?
это правильно:
for (std::vector<Day *>::iterator i = vector_day.begin(); i != vector_day.end(); ++i) {
delete *i;
}
не делает ли это недействительным вектор при каждом удалении? Я в полном замешательстве.
10 ответов
лучший способ - не помещать указатели в вектор в первую очередь, если вам это абсолютно не нужно.
но если вам действительно нужно иметь вектор указателей, то способ, которым вы это делаете, просто прекрасен (но .clear()
векторные послесловия, Если он не будет немедленно уничтожен, так что он не полон болтающихся указателей)
заявление
delete *it;
не влияет на итератор. Он не изменяет итератор, не делает итератор недействительным или удалить указатель ссылается итератор из коллекции. Все это делает свободная память, что указатель ссылается итератор указывает на. Указатель должен быть удален из коллекции по отдельности.
другой способ C++ сделать это-определить вспомогательную структуру:
struct delete_ptr { // Helper function to ease cleanup of container
template <typename P>
void operator () (P p) {
delete p;
}
};
а затем используйте алгоритмы:
std::for_each(vector_day.begin(), vector_day.end(), delete_ptr());
vector_day.clear();
В общем в C++ вы должны скрыть управление памятью как можно больше, чтобы избежать ошибок памяти. Если вы не делаете много копирования указателей и не заботитесь о производительности, я бы просто использовал shared_ptr.
Он является частью стандарта TR1 и доступен в большинстве современных компиляторов C++ из коробки (http://anteru.net/2008/09/01/260/) и больш для пожара и забывает управление памяти.
вероятно, вы должны использовать какой-то управляемый указатель, скорее всего, общий указатель.
Если вы удалите вектор, пока кто-то еще держится за один из этих указателей, вы получите очень неприятное поведение, если они попытаются разыграть его. Общий указатель избавит вас от головной боли.
Если вы можете гарантировать, что ничто другое не будет ссылаться на указатели после удаления вектора, вы все равно можете использовать автоматический указатель. Он будет управлять освобождением для вас, когда вектор будет уничтожен. Накладные расходы минимальны, и это делает вашу жизнь намного проще.
операции, которые добавляют или удаляют элементы из массива, могут сделать итераторы недействительными, проверьте документацию для определенных правил для разных типов контейнеров. С delete
, вы действуете на данные, содержащиеся в элементах массива, а не на форму массива. Итераторы пересекают форму контейнера, они не заботятся о его содержимом.
прежде всего, вы перешли от i
до it
, но я предполагаю, что это просто опечатка.
но чтобы ответить на ваши поиски, нет, все в порядке. Ты не меняешься it
, вы изменяете *it
.
все в порядке. Удалении *i
(объект, на который указывает элемент вектора), а не i
(элемент вектора), поэтому вектор не является недействительным.
посмотреть этот вопрос для случая, когда разработчик также хотел удалить все i
s, и для решения для него (vector_day.clear()
) после цикла.
вот удобный класс, который я написал некоторое время назад, имея дело с той же проблемой. Я преобразовывал некоторый код из старых векторов и списков на основе RogueWave в векторы и списки на основе STL и нуждался в некотором способе эмуляции метода clearAndDestroy() RW для списков указателей. Метод clearAndDestroy () можно переопределить для обработки различных типов структур (я включил только вектор здесь для краткости).
class StlUtils
{
public:
/**
* This method provides a templated way to destroy a std::vector
* full of pointers. It is basically a replacement for the RW
* vector class' clearAndDestroy methods. The list argument is
* returned empty.
*
* @param list the list of pointers to be destroyed.
*/
template<class T> static void clearAndDestroy(
std::vector<T*> &itemList)
{
for_each(itemList.begin(), itemList.end(),
stl_deleter<T>());
itemList.clear();
}
private:
/**
* Templated member function for use with the clearAndDestroy()
* method. It provides the method needed by for_each to do the
* actual deletion.
*/
template<class T> struct stl_deleter
{
void operator() (T* x) {
if (x != NULL)
delete x;
}
};
};
другой способ итерации + удаления-использовать while(!empty)
петли.
Преимущество этого метода заключается в том, что элемент сначала удаляется из контейнера, удаляются послесловия. Это безопасно для любого контейнера:
while (!vector_day.empty()) {
Day* day = vector_day.back();
vector_day.pop_back();
delete day;
}