C ++ удаляет указатель на указатель - PullRequest
20 голосов
/ 07 сентября 2008

Итак, у меня есть указатель на массив указателей. Если я удалю это так:

delete [] PointerToPointers;

Это также удалит все указанные указатели? Если нет, нужно ли перебирать все указатели и удалять их, или есть более простой способ сделать это? Мой гугл-фу, похоже, не дает мне хороших ответов на этот вопрос.

(И да, я знаю, что мне нужно использовать вектор. Это одно из тех заданий типа «догнать С ++» в школе.)

Ответы [ 7 ]

29 голосов
/ 07 сентября 2008

Да, вы должны перебирать указатели, удаляя по отдельности.

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

Для «более простого способа» два предложения: (1) Создайте подпрограмму для этой цели, чтобы, по крайней мере, вам не пришлось писать код более одного раза. (2) Используйте парадигму разработки «умный указатель», в которой вы храните массив объектов со счетчиками ссылок, после чего объекты удаляются, когда на объекты больше не ссылается какой-либо код.

18 голосов
/ 07 сентября 2008

Я согласен с Джейсоном Коэном, хотя мы можем быть немного яснее о причине необходимости удаления ваших указателей с помощью цикла. Для каждого «нового» или динамического выделения памяти необходимо «удалить» выделение памяти. Иногда «удалить» можно скрыть, как со смарт-указателями, но он все еще там.

int main()
{
  int *pI = new int;
  int *pArr = new int[10];

пока в коде мы выделили два фрагмента динамической памяти. Первый - это просто общее, а второй - массив целых.

  delete pI;
  delete [] pArr;

эти операторы удаления очищают память, выделенную "новыми" s

  int ppArr = new int *[10];

  for( int indx = 0; indx < 10; ++indx )
  {
    ppArr[indx] = new int;
  }

Этот бит кода выполняет оба предыдущих распределения. Сначала мы создаем пространство для нашего int в динамическом массиве. Затем нам нужно выполнить цикл и выделить int для каждой точки в массиве.

  for( int indx = 0; indx < 10; ++indx )
  {
    delete ppArr[indx];
  }
  delete [] ppArr;

Обратите внимание на порядок, в котором я выделил эту память, а затем удалил ее в обратном порядке. Это потому, что если бы мы делали delete [] ppArr; Сначала мы потеряем массив, который говорит нам, каковы наши другие указатели. Этот кусок или память будут возвращены в систему и, следовательно, более не будут надежно считываться.

  int a=0;
  int b=1;
  int c=2;

  ppArr = new int *[3];

  ppArr[0] = &a;
  ppArr[1] = &b;
  ppArr[2] = &c;

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

  delete [] ppArr;

  return 0;

}

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

4 голосов
/ 12 сентября 2008

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

3 голосов
/ 29 сентября 2010

Давайте возьмем (псевдокодированный) пример из реального мира. Представьте, что у вас был такой класс:

class Street
{
    public:
        Street();
        ~Street();
    private:
        int HouseNumbers_[];
}

typedef *Street StreetSign;

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

Массив указателей (концептуально) немного похож на массив целых чисел, это массив чисел, представляющих ячейки памяти различных объектов. Это не сами объекты.

Если вы удалите [] массив указателей, все, что вы сделали, это удалили массив целых чисел.

3 голосов
/ 07 сентября 2008

Указатели - это всего лишь ссылки на память, а не небольшие, самоочищающиеся объекты .net. Создание надлежащих деструкторов для каждого класса сделает удаление немного чище, чем массивные циклы в коде.

1 голос
/ 07 сентября 2008

Я думаю, тебе придется зацикливаться, боюсь.

0 голосов
/ 15 апреля 2009

Я не знаю, почему на этот вопрос ответили так смущающе долго.

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

Вы удалили кучу адресов, но без объектов.

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

Неважно, что он просто удалил кучу адресов объектов, он просто видит целые.

Вот почему вы должны сначала пройтись по массиву! и позвони удалить для каждого элемента вы можете удалить хранилище самого массива.

Ну, теперь мой ответ стал несколько длиннее ... .... странно ...;)

Edit: Ответ Джейсона не ошибочный, он просто не в состоянии попасть в точку. ни компилятор или что-либо еще в c (++) заботится о том, чтобы вы удалили что-то, находящееся в другом месте указал на. Вы можете просто сделать это. Другие части программы, пытающиеся использовать удаленные объекты будет сегфо на вас. Но никто не помешает вам. Также не будет проблемой уничтожить массив указателей на объекты, когда объекты ссылки в другом месте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...