массивы — C ++ delete [] void * любопытство

У меня довольно простая, хотя и большая, настройка системы. Он хранит свои данные в void* массив, потому что данные, которые он хранит, могут варьироваться между float или же double в зависимости от того, сколько точности требуется.

просто делаю delete [] data поднимает warning: deleting 'void*' is undefined [enabled by default] используя MinGW. И у меня есть другая переменная, чтобы сказать мне, если data это float* или double*, но имеет ли значение, какой я использую?

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

double* d_data = new double[length];
data = (void*)d_data;
delete [] (float*)data;

1

Решение

Это, безусловно, имеет значение; указатель, который вы используете для delete[] должен иметь тот же тип, что и указатель, который вы выделили. Так что кастинг double* допустимо (но подвержено ошибкам); приведение к float* дает неопределенное поведение.

[Существует исключение для отдельных объектов (не массивов) типов классов — это может быть указатель на базовый класс, если этот базовый класс имеет виртуальный деструктор. Но это не относится к примитивным типам, таким как doubleили массивам.]

Что касается утечек памяти: ручное управление памятью всегда несет в себе опасность утечки памяти, если только вы не будете очень осторожны, никогда не делайте ничего, что могло бы вызвать исключение. Я настоятельно рекомендую использовать RAII управлять всеми динамическими ресурсами.

3

Другие решения

Кажется, вы можете использовать союз.

1

Да, это важно (и приведение к другому типу данных, по сути, так же плохо, как уход void*), потому что вы по существу теряете / портите дополнительные метаданные (например, действительную длину). Это не обязательно может произойти сбой (например, вы можете использовать delete data; скорее, чем delete [] data; а также, что произойдет, если компилятор не заметит ошибку), поскольку это по сути неопределенное поведение (разные компиляторы или версии могут генерировать разные результаты).

Как предположил Хорхе, вы можете просто использовать для этого объединение, чтобы два типа данных могли совместно использовать одну и ту же память:

union my_union {
double d_double;
float d_float;
};

В зависимости от компилятора эта структура обычно будет иметь тот же размер, что и самый большой тип данных внутри (в данном случае (и на 32-битной машине), вероятно, 8 байтов для двойного, 4 байта для плавающего; таким образом, общий размер будет 8 байты, потому что эти переменные по существу перекрываются). Просто помните, что вы не можете использовать это для какого-то автоматического преобразования.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector