Каков правильный способ освобождения std::vector указателей в С++?

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

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

Не делает ли это аннулирование вектора при каждом удалении? Я очень смущен.

Ответы

Ответ 1

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

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

Утверждение

delete *it;

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

Ответ 2

Настроить ptr_vector на помощь!

Именно то, что вам нужно, без необходимости повторять и удалять содержимое std::vector

Ответ 3

Другой способ С++ для этого - определить вспомогательную структуру:

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();

Ответ 4

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

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

Ответ 5

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

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

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

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

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

Ответ 9

Вот удобный класс, который я написал некоторое время назад, имея дело с той же проблемой. Я конвертировал некоторый код из старых векторов на основе RogueWave и списки в векторы и списки на основе STL и нуждался в некотором способе эмулировать метод RW clearAndDestroy() для списков указателей. Метод 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;
         }
      };
};