Будет ли использование удаления с указателем базового класса вызвать утечку памяти?

17

Учитывая, что два класса имеют только примитивный тип данных и не имеют специального деструктора / деаллокатора. Предоставляет ли спецификация C ++ его освобождение с правильным размером?

struct A { int foo; };
struct B: public A { int bar[100000]; };
A *a = (A*)new B;
delete a;

Я хочу знать, нужно ли писать пустой virtual dtor?

Я пробовал g ++ и vc ++ 2008, и они не вызовут утечки. Но я хотел бы знать, что правильно в стандарте C ++.

    
задан kcwu 20.01.2010 в 11:32
источник
  • У меня была самая серьезная ошибка в моей жизни, когда я смешивал наследование без виртуальных методов с пулом памяти. Просто не делай этого, это небезопасно. –  vava 20.01.2010 в 11:38

5 ответов

23

Если деструктор базового класса виртуальный, это неопределенное поведение. См. 5.3.5 / 4:

  

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

    
ответ дан James Hopkin 20.01.2010 в 11:39
источник
  • То есть находится в n3242 по 5.3.5 / ** 3 **. Ни один из ответов не объясняет, что происходит, если у вас есть виртуальный деструктор. Мы только беспокоимся о деструкторе здесь? Разрушитель в стороне, будет ли «удаленный» подкласс удалено из памяти? Если это так, то подклассы, которые не нуждаются в деструкторах, не будут течь. –  Nathan Goings 22.06.2013 в 07:36
  • @Nathan: если базовый класс имеет виртуальный деструктор, все работает. В противном случае поведение не определено. Когда есть виртуальный деструктор, все деструкторы вызываются (каждый производный класс в цепочке имеет виртуальный деструктор, даже если он не объявлен виртуальным или явно не определен) и память очищается. –  James Hopkin 30.01.2014 в 13:59
16

В соответствии со стандартом C ++ у вас есть неопределенное поведение - это может проявиться как утечка, может и не так. Для правильного кода вам нужен виртуальный деструктор.

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

    
ответ дан anon 20.01.2010 в 11:35
источник
1

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

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

    
ответ дан sharptooth 20.01.2010 в 11:37
источник
1

Только для примитивных данных, я считаю, что все в порядке. В этом случае вы вряд ли захотите понести стоимость v-таблицы. В противном случае виртуальный д'ор определенно предпочтителен.

    
ответ дан psychotik 20.01.2010 в 11:38
источник
0

Он освободится от правильного размера, потому что размер, который должен быть освобожден, является свойством области памяти кучи, которую вы получили (размер, переданный на free() -подобные функции, отсутствует)!

Тем не менее, никто не вызывается. Если «B» определяет деструктор или содержит какие-либо элементы с нетривиальным деструктором, они не будут вызваны, что вызовет утечку потенциальной памяти. Однако это не относится к вашему образцу кода.

    
ответ дан Alexander Gessler 20.01.2010 в 11:36
источник
  • Где вы видите «свободную функцию»? Одна из причин, по которой C ++ использует оператор delete вместо функции, является прямой реализацией компилятора. Компилятор знает sizeof (A), и он также знает, что A не имеет виртуального деструктора, поэтому разрешено вызывать FourBytePool :: free (void * p) за кулисами. –  MSalters 21.01.2010 в 12:08