2008-09-16 3 views
10

Скажем, у меня есть следующий C++:удаление буфера с помощью другого типа указателя?

char *p = new char[cb]; 
SOME_STRUCT *pSS = (SOME_STRUCT *) p; 
delete pSS; 

Безопасно ли это в соответствии со стандартом C++? Нужно ли возвращать обратно в char*, а затем использовать delete[]? Я знаю, что он будет работать в большинстве компиляторов C++, потому что это обычные обычные данные без деструкторов. Гарантировано ли это безопасно?

ответ

6

Нет, это неопределенное поведение - компилятор может правдоподобно сделать что-то другое, и, как говорит C++ запись FAQ, что thudbang связан с, operator delete[] могут быть перегружены, чтобы сделать что-то другое operator delete. Вы можете иногда уйти от него, но также хорошей практикой является привычка сопоставлять delete [] с новым [] для случаев, когда вы не можете.

0

Хотя это должна работа, я не думаю, что вы можете гарантировать, что это будет безопасно, потому что SOME_STRUCT не символ * (если это не просто ЬурейеЕ).

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

2

C++ Standard [5.3.5.2] заявляет:

Если операнд имеет тип класса, операнд преобразуется к типу указателя путем вызова Вышеупомянутый Конверсиям функции, и преобразованный операнд является используется вместо исходного операнда для остальной части этого раздела. В альтернативе значение операнда удаления может быть значением нулевого указателя. Если это не значение нулевого указателя, в первом альтернативе (удалить объект) значение операнда delete должно быть указателем на объект без массива или указателем на подобъект (1.8) , представляющий базу класс такого объекта (п. 10). Если нет, поведение не определено. Во втором альтернативном (удалить массив) значение операнда delete должно быть значением указателя, которое было результатом предыдущего массива new-expression.77) Если нет, поведение не определено. [Примечание: это означает, что синтаксис delete-expression должен соответствовать типу объекта, назначенного новым, а не синтаксису нового выражения. -end note] [Примечание: указатель на тип const может быть операндом выражения-удаления; нет необходимости отбрасывать константу (5.2.11) выражения указателя до того, как он будет использоваться как операнд выражения-удаления. -end note]

4

Я очень сомневаюсь.

Есть много сомнительных способов освобождения памяти, например, вы можете использовать delete на вашем char массива (а не delete[]), и это, скорее всего, работать нормально. I blogged об этом (извинения за самонаводку, но это проще, чем переписывать все это).

Компилятор - это не столько проблема, как платформа. Большинство библиотек будут использовать методы распределения базовой операционной системы, что означает, что один и тот же код может вести себя по-разному на Mac против Windows против Linux. Я видел примеры этого, и каждый из них был сомнительным кодом.

Самый безопасный подход - всегда выделять и освобождать память с использованием одного и того же типа данных. Если выделения char с и возвращает их в другой код, вы можете быть лучше предоставления конкретных выделить/DEALLOCATE методы:

SOME_STRUCT* Allocate() 
{ 
    size_t cb; // Initialised to something 
    return (SOME_STRUCT*)(new char[cb]); 
} 

 

void Free(SOME_STRUCT* obj) 
{ 
    delete[] (char*)obj; 
} 

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

0

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

Единственный случай, когда это нормально с не-POD-типами, является то, что pointee является подтипом указателя (например, вы указываете автомобиль с транспортным средством *), а деструктор указателя объявлен виртуальным.

0

Это небезопасно, и не ответы до сих пор подчеркивали безумие этого. Просто не делайте этого, если считаете себя настоящим программистом или когда-либо хотите работать профессиональным программистом в команде. Вы можете только сказать, что ваша структура содержит non destructor на данный момент, однако вы закладываете противный компилятор и системную ловушку для будущего. Кроме того, ваш код вряд ли будет работать так, как ожидалось. Самое лучшее, на что вы можете надеяться, это не крушение. Однако я подозреваю, что вы медленно получите утечку памяти, так как распределение массивов через новые очень часто выделяет дополнительную память в байтах до возвращенному указателю. Вы не освободите память, о которой вы думаете. Хорошая процедура распределения памяти должна поднять это несоответствие, так же как и инструменты, такие как Lint и т. Д.

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

0

Я изменил код, чтобы использовать malloc/free. В то время как я знаю, как MSVC реализует новый/delete для простых-старых данных (и SOME_STRUCT в этом случае была структурой Win32, настолько простой C), я просто хотел знать, была ли это переносная техника.

Это не так, поэтому я буду использовать что-то, что есть.

0

Если вы используете malloc/free вместо new/delete, malloc и free не заботятся о типе.

Итак, если вы используете C-подобный POD (простые старые данные, такие как встроенный тип или структура), вы можете malloc какого-то типа и освободить другого. Обратите внимание, что это плохой стиль, даже если он работает.

2

Это очень похожий вопрос к тому, что я ответил здесь: link text

Короче говоря, нет, это не безопасно в соответствии со стандартом C++.Если по какой-то причине вам нужен объект SOME_STRUCT, выделенный в области памяти с разницей в размере от size_of(SOME_STRUCT) (и лучше было бы больше!), Тогда вам лучше использовать функцию выделения выделения, такую ​​как глобальная operator new, для выполнения а затем создание экземпляра объекта в необработанной памяти с размещением new. Размещение new будет чрезвычайно дешевым, если у объекта нет конструктора.

void* p = ::operator new(cb); 
SOME_STRUCT* pSS = new (p) SOME_STRUCT; 

// ... 

delete pSS; 

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

::operator new и ::operator delete являются ближайшим эквивалентом C++ 's к malloc и free и в них (при отсутствии класса переопределяет) называются уместными new и delete выражения они могут (с осторожностью!) Можно использовать в комбинации.

Смежные вопросы