C ++ Dynamic Allocation Mismatch: это проблематично? - PullRequest
4 голосов
/ 07 июня 2010

Мне поручили работать над неким устаревшим кодом C ++ в MFC. Одной из вещей, которые я нахожу повсюду, являются распределения, подобные следующим:

struct Point
{
   float x,y,z;
};

...

void someFunc( void )
{
   int numPoints = ...;
   Point* pArray = (Point*)new BYTE[ numPoints * sizeof(Point) ];
   ...
   //do some stuff with points
   ...
   delete [] pArray;
}

Я понимаю, что этот код ужасно неверен на многих уровнях (приведение в стиле C, использование new, как malloc, сбивание с толку и т. Д.). Я также понимаю, что если бы Point определил конструктор, он не был бы вызван, и странные вещи произошли бы в delete [], если бы был определен деструктор.

Вопрос: Я нахожусь в процессе исправления этих происшествий, где бы они ни возникали как нечто само собой разумеющееся. Однако я никогда не видел ничего подобного раньше, и это заставило меня интересно. Может ли этот код вызвать утечку / повреждение памяти в текущем состоянии (без конструктора / деструктора, но с несоответствием типов указателей) или он безопасен, если массив содержит только структуры / примитивные типы?

Ответы [ 4 ]

6 голосов
/ 07 июня 2010

Формально код вызывает неопределенное поведение из-за несоответствия типов указателей в new[] / delete[]. На практике это должно работать нормально.

Проблему несоответствия типов указателей легко устранить, добавив приведение к выражению delete

delete [] (BYTE *) pArray;

Если тип Point определен так, как показано в вопросе (то есть с помощью тривиального конструктора и деструктора), то это исправление решает все формальные проблемы, присутствующие в этом коде. С языковой точки зрения время жизни объекта с тривиальным конструктором (деструктором) начинается (заканчивается) одновременно с продолжительностью его хранения. То есть нет необходимости выполнять фактический вызов конструктора (деструктора).

1 голос
/ 07 июня 2010

Пока конструкторы и деструкторы ничего не делают, вы в безопасности.

0 голосов
/ 07 июня 2010

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

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

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

И если, наконец, вы решили продолжить изменение, зачем останавливаться на полпути? Рассмотрите возможность избавления от всех new s и delete в целом и замените их на vector s и т. Д.

0 голосов
/ 07 июня 2010

Пока вы гарантируете, что он действительно вызывает совпадение delete[] для каждого new[], он не должен просачиваться - но если исключение может быть вызвано любым из закомментированного кода, быть трудно уверенным (в основном, вам нужно перехватить любые возможные исключения, удалить память, а затем повторно выбросить исключение).

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