Куча коррупции - PullRequest
       18

Куча коррупции

1 голос
/ 30 июля 2009

Почему это проблема, если у нас есть огромный кусок кода между new и delete из массива char.

* ** 1003 тысяча два * Пример
void this_is_bad() /* You wouldn't believe how often this kind of code can be found */
{
  char *p = new char[5];    /* spend some cycles in the memory manager */
  /* do some stuff with p */
  delete[] p;      /* spend some more cycles, and create an opportunity for a leak */
}

Ответы [ 8 ]

8 голосов
/ 30 июля 2009

Потому что кто-то может выбросить исключение.
Потому что кто-то может добавить возврат.

Если у вас много кода между новым и удаленным, вы можете не заметить, что вам нужно освободить память перед броском / возвратом?

Почему в вашем коде есть указатель RAW.
Используйте std :: vector.

5 голосов
/ 30 июля 2009

В статье, на которую вы ссылаетесь, говорится, что

 char p[5]; 

будет столь же эффективным в этом случае и не будет опасности утечки.

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

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

2 голосов
/ 30 июля 2009

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

Я бы различал «количество работы» и «количество кода»:

void do_stuff( char* const p );

void formerly_huge_function() {
   char* p = new char[5];
   CoInitialize( NULL );
   do_stuff( p );
   CoUninitialize();
   delete[] p;
}

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

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

2 голосов
/ 30 июля 2009

Ссылка (и источник) этого кода оплакивает ненужное использование кучи в этом коде. Для постоянного и небольшого объема памяти нет причины , а не , чтобы выделять ее в стеке.

Вместо

void this_is_good()
{
   /* Avoid allocation of small temporary objects on the heap*/
   char p[5];    /* Use the stack instead */
   /* do some stuff */
}

Хотя в исходном коде нет ничего плохого по сути, его просто меньше оптимального.

1 голос
/ 30 июля 2009

Этот конкретный пример не говорит о том, что иметь кучу кода между new и delete обязательно плохо; в нем говорится, что если есть способы написания кода, который не использует кучу, вы можете предпочесть это, чтобы избежать повреждения кучи.

Это достаточно приличный совет; если вы уменьшите количество используемой кучи, вы будете знать, где искать поврежденную кучу.

0 голосов
/ 30 июля 2009

Вы спрашиваете, будет ли это лучше?

void this_is_great()
{
   char* p = new char[5];
   delete[] p;
   return;
 }

Это не так.

0 голосов
/ 30 июля 2009

Нет, если предположить, что «огромный кусок кода»:

  1. Всегда запускает "delete [] p;" перед вызовом "p = new char [size];" или «выбросить исключение»
  2. Всегда работает "p = 0;" после вызова "delete [] p;"

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

0 голосов
/ 30 июля 2009

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

Что может привести к неприятностям, когда у вас есть огромное количество кода в одном и том же методе между new и delete, так это вероятность случайной утечки переменной из-за ...

  • Исключение выдается
  • Методы, которые становятся такими длинными, что вы не видите начала или конца, и поэтому люди начинают произвольно возвращаться с середины, не осознавая, что пропустили вызов удаления

И то, и другое можно исправить, используя тип RAII, такой как std::vector<char>, вместо пары new / delete.

...