Что является правильным способом освободить станд.:: вектор указателей в C++?

Я искал StackOverflow, но не мог найти ответ на этот вопрос.

Предположим, что у меня есть a std::vector<Day *> vector_day - это - вектор указателей на Day объект. Теперь я push_back кому: 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;
}

Разве это не делает недействительным вектор на каждом удалении? Я очень смущен.

16
задан Brian Tompsett - 汤莱恩 8 July 2015 в 22:00
поделиться

9 ответов

Лучший способ - не помещать указатели в вектор в первую очередь, если в этом нет крайней необходимости.

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

Оператор

delete *it;

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

18
ответ дан 30 November 2019 в 17:26
поделиться

Boost ptr_vector на помощь!

Делает именно то, что вам нужно, без необходимости итерации и удаления содержимого std::vector

7
ответ дан 30 November 2019 в 17:26
поделиться

Another C++ way to do this is to define a helper struct:

struct delete_ptr { // Helper function to ease cleanup of container
    template <typename P>
    void operator () (P p) {
        delete p;
    }
};

and then use the algorithms:

std::for_each(vector_day.begin(), vector_day.end(), delete_ptr());
vector_day.clear();
4
ответ дан 30 November 2019 в 17:26
поделиться

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

Это часть стандарта TR1, доступная в большинстве современных компиляторов C ++ из коробки ( http://anteru.net/2008/09/01/260/ ) и отлично подходит для пожара. и забудьте об управлении памятью.

2
ответ дан 30 November 2019 в 17:26
поделиться

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

0
ответ дан 30 November 2019 в 17:26
поделиться

Вероятно, вам следует использовать какой-то управляемый указатель, скорее всего, общий указатель.

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

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

1
ответ дан 30 November 2019 в 17:26
поделиться

Ничего страшного. Вы удаляете * i (объект, на который указывает элемент вектора), а не i (элемент вектора), поэтому вектор не становится недействительным.

См. этот вопрос для случая, когда разработчик также хотел удалить все i s, и решение для этого ( vector_day.clear () ) после цикла.

0
ответ дан 30 November 2019 в 17:26
поделиться

Вот удобный класс, который я написал некоторое время назад, когда занимался той же проблемой. Я преобразовывал некоторый код из старых векторов и списков на основе 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;
         }
      };
};
0
ответ дан 30 November 2019 в 17:26
поделиться

Прежде всего, вы переключились с i на it , но я предполагаю, что это всего лишь опечатка.

Но ответить на ваш квест - нет, это нормально. Вы не меняете it , вы меняете * it .

0
ответ дан 30 November 2019 в 17:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: