D>class A {};
D>class B : public A
D>{
D> int i[1000];
D>};
D>int main()
D>{
D> A *a = new B();
D> delete a; // будет ли здесь утечка?
D> return 0;
D>}
D>
D>Как я понимаю, удаляется sizeof(*a). Это 1, а не 1000. D>Наверное, я что-то упустил при изучении наследования. D>valgrind не видит утечки.
Всего лишь не вызовется деструктор B. Утечки таки не будет.
int main()
{
void *a = new B();
delete a; // и сколько, по-вашему, здесь байт удаляется? :) return 0;
}
D>class A {};
D>class B : public A
D>{
D> int i[1000];
D>};
D>int main()
D>{
D> A *a = new B();
D> delete a; // будет ли здесь утечка?
D> return 0;
D>}
D>
D>Как я понимаю, удаляется sizeof(*a). Это 1, а не 1000.
Код содержит неопределенное поведение. Дли исправления ситуации деструктор A нужно сделать виртуальным.
D>Наверное, я что-то упустил при изучении наследования.
Да, похоже на то
D>valgrind не видит утечки.
Одно из проявлений неопределенного поведения
D>class A {};
D>class B : public A
D>{
D> int i[1000];
D>};
D>int main()
D>{
D> A *a = new B();
D> delete a; // будет ли здесь утечка?
D> return 0;
D>}
D>
D>Как я понимаю, удаляется sizeof(*a). Это 1, а не 1000. D>Наверное, я что-то упустил при изучении наследования. D>valgrind не видит утечки.
А вы вот так попробуйте:
class A {};
class B : public A
{
public:
B()
: s_(new char[10])
{}
~B()
{
delete [] s_;
}
private:
char * s_;
}
A * a = new B();
delete a;
dronord wrote:
> class A {}; > class B : public A > { > int i[1000]; > }; > > int main() > { > A *a = new B(); > delete a; // будет ли здесь утечка? > return 0; > }
> Наверное, я что-то упустил при изучении наследования. > valgrind не видит утечки.
Я просто в шоке — этот вопрос обсуждается практически каждый месяц, и все равно всегда находятся люди, гнотовые спорить по этому поводу
5.3.5/3
In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual
destructor or the behavior is undefined.
B>Я просто в шоке — этот вопрос обсуждается практически каждый месяц, и все равно всегда находятся люди, гнотовые спорить по этому поводу
B>
B>5.3.5/3
B>In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual
B>destructor or the behavior is undefined.
Спасибо за стандарт! Также нашел в книге Б.Страуструп 3е изд., стр.477, "15.6 Свободная память"
Скажите, а массив вообще не удастся удалить?
In the second alternative (delete array) if the dynamic type of the
object to be deleted differs from its static type, the behavior is undefined.
И>у класса A должен быть виртуальный деструктор.
B::~B() сделает смещение в памяти на 1000 байт?
Не знаю, где искать в стандарте языка. В нем это есть?
Мне кажется:
delete a; потом free(a); a->~B();
free() освободит sizeof(*a) и 1000 байт останутся как используемые.
Деструктор же это просто функция и понятия об атрибутах класса не имеет.
Я прав?
Здравствуйте, dronord, Вы писали:
И>>у класса A должен быть виртуальный деструктор. D>B::~B() сделает смещение в памяти на 1000 байт? D>Не знаю, где искать в стандарте языка. В нем это есть?
в стандарте языка это есть.
в общем, здесь два пути рарзешения проблемы:
1. рекомендованный. у базового класса должен быть виртуальный деструктор. тогда оператор delete вызовет деструктор конкретного типа, а не того, который ему подсунули.
2. сделать явное приведение типов, например
Здравствуйте, dronord, Вы писали:
D>Как я понимаю, удаляется sizeof(*a). Это 1, а не 1000. D>Наверное, я что-то упустил при изучении наследования. D>valgrind не видит утечки.
Вообще-то в стандарте это опреелено, как UB, так что может быть что угодно.
Но в реальных системаз аллокаторы обычно устроены так, что получают на вход указатель на начало блока, а рамер блока находят как-то сами (кури описание функции operator delete( void * ) ).
Это, например, аналогично C-шной традиции, когда писали alloc и free. При этов во free hfpvth блока не передавали.
Так что на большинстве реальных систем утечки не будет...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, alexeiz, Вы писали:
A>А вы вот так попробуйте: A>
A>class A {};
A>class B : public A
A>{
A>public:
A> B()
A> : s_(new char[10])
A> {}
A> ~B()
A> {
A> delete [] s_;
A> }
A>private:
A> char * s_;
A>}
A>A * a = new B();
A>delete a;
A>
A>С вас $30
Если я не ошибаюсь то с вас надо брать в несколько раз больше.
Так как виртуального деструктора у класса A так и не появилось
A>
A>class A {
public:
virtual ~A(){}
};
class B : public A
{
int i[1000];
};
int main()
{
A *a = new B();
delete a; // будет ли здесь утечка?return 0;
}
D>class A {};
D>class B : public A
D>{
D> int i[1000];
D>};
D>int main()
D>{
D> A *a = new B();
D> delete a; // будет ли здесь утечка?
D> return 0;
D>}
D>
D>Как я понимаю, удаляется sizeof(*a). Это 1, а не 1000. D>Наверное, я что-то упустил при изучении наследования. D>valgrind не видит утечки.
Я думаю примерно так: "delete a" разбивается на 2 части:
— вызов деструктора ~A (действительно невиртуального)
— вызов operator delete (который собственно и освободит память)
По первой части: течь нечему, всё тривиально (хотя в более сложном случае может и потечь)
По второй части: будет освобождена вся выделенная память размером sizeof (B)
Здравствуйте, игппук, Вы писали:
И>не надо с него больше брать. человек намеренно привел немного расширенный код автора, чтобы показать, в как получить конкретную утечку.
Здравствуйте, dronord, Вы писали:
D>Скажите, а массив вообще не удастся удалить?
Ну, если тебе плевать на UB, и деструкторы тривиальные, то удастся конечно, на большинстве реализаций...
В этом смысле ситуация такая же, как с уалением одного объекта, без виртуального деструктора.
Но с массивом есть большая беда. Кроме того, что его не удастся удалить, с ним вообе ничего сделать не удастся, на самом деле
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, dronord, Вы писали:
D>>Скажите, а массив вообще не удастся удалить?
E>Ну, если тебе плевать на UB, и деструкторы тривиальные, то удастся конечно, на большинстве реализаций... E>В этом смысле ситуация такая же, как с уалением одного объекта, без виртуального деструктора.
Можешь привести пример такой реализации?
Я до сих пор встречал только один случай, где массив наследников корректно удалялся через указатель на базу (здесь
D>class A {};
D>class B : public A
D>{
D> int i[1000];
D>};
D>int main()
D>{
D> A *a = new B();
D> delete a; // будет ли здесь утечка?
D> return 0;
D>}
D>
D>Как я понимаю, удаляется sizeof(*a). Это 1, а не 1000. D>Наверное, я что-то упустил при изучении наследования. D>valgrind не видит утечки.
Здесь 2 альтернативы —
1. Сделать виртуальный деструктор у класса А.
2. Сделать деструктор класса А скрытым. Тогда код вообще перестанет компилироваться.
То, что вы привели — это неопределённое поведение. Худший случай — если у вас не будет утечек памяти и всё будет работать нормально. А потом при смене\обновлении компилятора или изменении каких-либо условий вы получите неожиданный сюрприз.
Здравствуйте, Bell, Вы писали:
E>>Ну, если тебе плевать на UB, и деструкторы тривиальные, то удастся конечно, на большинстве реализаций... E>>В этом смысле ситуация такая же, как с уалением одного объекта, без виртуального деструктора.
B>Можешь привести пример такой реализации? B>Я до сих пор встречал только один случай, где массив наследников корректно удалялся через указатель на базу (здесь
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, elcste, Вы писали:
E>Собственно, я не знаю реализаций, где этот код откомпилируется.
Ты про точку с запятой после struct S1 { char F1; }? Это скучно.
Network Access Message: The website cannot be found
ссылка чего-то не работает.
Не расскажешь что там было написано.
На всяк. случай -- MSVC от 6 до 2003 вроде как кушают и не чихают...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском