Динамически распределяемая структура и кастинг - PullRequest
2 голосов
/ 13 апреля 2010

Допустим, у меня есть первая структура, подобная этой:

typedef struct {
    int  ivalue;
    char cvalue;
}
Foo;

И второй:

typedef struct {
    int  ivalue;
    char cvalue;
    unsigned char some_data_block[0xFF];
}
Bar;

Теперь допустим, я делаю следующее:

Foo *pfoo;
Bar *pbar;

pbar = new Bar;

pfoo = (Foo *)pbar;

delete pfoo; 

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

sizeof(int) + sizeof(char)  

Или

sizeof(int) + sizeof(char) + sizeof(char) * 0xFF

А если это первый случай из-за приведения, есть ли способ предотвратить утечку памяти?

Примечание: пожалуйста, не отвечайте "использовать полиморфизм C ++" или подобное, я использую этот метод по причине.

Ответы [ 6 ]

9 голосов
/ 13 апреля 2010

Объем свободной памяти не определен - ваш код недопустим в C ++.

5 голосов
/ 13 апреля 2010

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

Тем не менее, рассматривать удаление как расширение до чего-то вроде:

if ( ptr != 0 ){
    ptr->~ClassName();
    operator delete(ptr);
}

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

Рассмотрим случай, когда операторы new и delete перегружены ...

1 голос
/ 13 апреля 2010

Вся идея такого кода - просто неопределенное поведение. Не делай этого. Что произойдет, если кто-то перегружает operator new и operator delete для одной структуры, а не для другой?

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

Однако, если operator new и operator delete не перегружены и обе структуры имеют тривиальные деструкторы, он может просто нормально работать в вашей реализации - компилятор вызовет ::operator delete(), который имеет один параметр - адрес блока, и он будет освободить точно нужное количество памяти. Однако не рассчитывайте на это - ваш код на самом деле имеет неопределенное поведение.

1 голос
/ 13 апреля 2010

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

0 голосов
/ 13 апреля 2010

Согласитесь с alemjerus - это не создает утечку памяти. Мои два цента: sizeof (int) + sizeof (char) не могут быть равны sizeof (Foo) из-за заполнения элементов структуры, поэтому размер выделенной / освобожденной памяти - sizeof (Foo).

0 голосов
/ 13 апреля 2010

Помимо вопросов языкового права, ваш код на практике будет делать правильные вещи и освобождать весь объект. Большинство компиляторов просто вызывают базовый malloc / free (или аналогичный) при вызове new / delete.

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

IIRC, отказ вызвать производный деструктор - единственное предупреждение с приведенным выше кодом. Кроме этого, я считаю, что это действительный код. (Мой C ++ ржавый в наши дни, так что я могу быть совсем не в порядке.)

...