наследование, delete, утечка
От: dronord  
Дата: 22.10.08 08:07
Оценка:
Здравствуйте.


class A {};
class B : public A
{
   int i[1000];
};

int main()
{
   A *a = new B();
   delete a;            // будет ли здесь утечка?
   return 0;
}



Как я понимаю, удаляется sizeof(*a). Это 1, а не 1000.
Наверное, я что-то упустил при изучении наследования.
valgrind не видит утечки.
Re: наследование, delete, утечка
От: игппук Беларусь  
Дата: 22.10.08 08:08
Оценка:
у класса A должен быть виртуальный деструктор.
проклятый антисутенерский закон
Re: наследование, delete, утечка
От: Bell Россия  
Дата: 22.10.08 08:12
Оценка: +1
Здравствуйте, dronord, Вы писали:

D>Здравствуйте.



D>
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 не видит утечки.

Одно из проявлений неопределенного поведения
Любите книгу — источник знаний (с) М.Горький
Re: наследование, delete, утечка
От: alexeiz  
Дата: 22.10.08 08:34
Оценка: -1
Здравствуйте, dronord, Вы писали:

D>Здравствуйте.



D>
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;


С вас $30
Re[2]: наследование, delete, утечка
От: dronord  
Дата: 22.10.08 09:01
Оценка:
И>у класса A должен быть виртуальный деструктор.
B::~B() сделает смещение в памяти на 1000 байт?
Не знаю, где искать в стандарте языка. В нем это есть?
Мне кажется:
delete a; потом free(a); a->~B();
free() освободит sizeof(*a) и 1000 байт останутся как используемые.
Деструктор же это просто функция и понятия об атрибутах класса не имеет.
Я прав?
Re[3]: наследование, delete, утечка
От: игппук Беларусь  
Дата: 22.10.08 09:04
Оценка:
Здравствуйте, dronord, Вы писали:

И>>у класса A должен быть виртуальный деструктор.

D>B::~B() сделает смещение в памяти на 1000 байт?
D>Не знаю, где искать в стандарте языка. В нем это есть?

в стандарте языка это есть.
в общем, здесь два пути рарзешения проблемы:
1. рекомендованный. у базового класса должен быть виртуальный деструктор. тогда оператор delete вызовет деструктор конкретного типа, а не того, который ему подсунули.
2. сделать явное приведение типов, например
delete (B*)a;
проклятый антисутенерский закон
Re: наследование, delete, утечка
От: Erop Россия  
Дата: 22.10.08 09:20
Оценка:
Здравствуйте, dronord, Вы писали:

D>Как я понимаю, удаляется sizeof(*a). Это 1, а не 1000.

D>Наверное, я что-то упустил при изучении наследования.
D>valgrind не видит утечки.

Вообще-то в стандарте это опреелено, как UB, так что может быть что угодно.
Но в реальных системаз аллокаторы обычно устроены так, что получают на вход указатель на начало блока, а рамер блока находят как-то сами (кури описание функции operator delete( void * ) ).

Это, например, аналогично C-шной традиции, когда писали alloc и free. При этов во free hfpvth блока не передавали.
Так что на большинстве реальных систем утечки не будет...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: наследование, delete, утечка
От: Camarada Россия  
Дата: 22.10.08 10:02
Оценка:
Здравствуйте, 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;
}


Вот так.
Re[3]: наследование, delete, утечка
От: игппук Беларусь  
Дата: 22.10.08 10:03
Оценка:
не надо с него больше брать. человек намеренно привел немного расширенный код автора, чтобы показать, в как получить конкретную утечку.
проклятый антисутенерский закон
Re: наследование, delete, утечка
От: McQwerty Россия  
Дата: 22.10.08 14:14
Оценка:
Здравствуйте, dronord, Вы писали:
D>
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)
Re: наследование, delete, утечка
От: MasterZiv СССР  
Дата: 22.10.08 15:50
Оценка: -1
dronord wrote:

> class A {};

> class B : public A
> {
> int i[1000];
> };
>
> int main()
> {
> A *a = new B();
> delete a; // будет ли здесь утечка?
> return 0;
> }

> Наверное, я что-то упустил при изучении наследования.

> valgrind не видит утечки.

Как можно увидеть то, чего нет ?
Posted via RSDN NNTP Server 2.1 beta
Re[2]: наследование, delete, утечка
От: MasterZiv СССР  
Дата: 22.10.08 15:51
Оценка: -1
игппук wrote:

> у класса A должен быть виртуальный деструктор.

Вовсе нет. Не обязан.
Posted via RSDN NNTP Server 2.1 beta
Re: наследование, delete, утечка
От: _Jane_ Украина  
Дата: 22.10.08 17:00
Оценка: -2
Здравствуйте, dronord, Вы писали:

D>
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;
}
Jane
Re[4]: наследование, delete, утечка
От: Camarada Россия  
Дата: 22.10.08 20:12
Оценка:
Здравствуйте, игппук, Вы писали:

И>не надо с него больше брать. человек намеренно привел немного расширенный код автора, чтобы показать, в как получить конкретную утечку.


Спасибо, дошло.
Re: Я просто в шоке
От: Bell Россия  
Дата: 23.10.08 03:18
Оценка: +1
Я просто в шоке — этот вопрос обсуждается практически каждый месяц, и все равно всегда находятся люди, гнотовые спорить по этому поводу

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.


Любите книгу — источник знаний (с) М.Горький
Re[2]: Я просто в шоке
От: dronord  
Дата: 23.10.08 06:00
Оценка: :)
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.

Это значит, нельзя писать:
void f(int n) {
   A *a = new B[n];
   delete []a;
}
?
Re[3]: Я просто в шоке
От: Bell Россия  
Дата: 23.10.08 06:15
Оценка:
Здравствуйте, dronord, Вы писали:

D>Спасибо за стандарт! ...

Пожалуйста

D>Скажите, а массив вообще не удастся удалить?

D>

In the second alternative (delete array) if the dynamic type of the
D>object to be deleted differs from its static type, the behavior is undefined.

D>Это значит, нельзя писать:
D>
void f(int n) {
D>   A *a = new B[n];
D>   delete []a;
D>}
?


Нельзя.
Вот одно из обсуждений подобного вопроса: здесь
Автор:
Дата: 30.11.05
Любите книгу — источник знаний (с) М.Горький
Re[3]: Я просто в шоке
От: Erop Россия  
Дата: 23.10.08 07:27
Оценка:
Здравствуйте, dronord, Вы писали:

D>Скажите, а массив вообще не удастся удалить?


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

Но с массивом есть большая беда. Кроме того, что его не удастся удалить, с ним вообе ничего сделать не удастся, на самом деле
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Я просто в шоке
От: Bell Россия  
Дата: 23.10.08 07:47
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, dronord, Вы писали:


D>>Скажите, а массив вообще не удастся удалить?


E>Ну, если тебе плевать на UB, и деструкторы тривиальные, то удастся конечно, на большинстве реализаций...

E>В этом смысле ситуация такая же, как с уалением одного объекта, без виртуального деструктора.

Можешь привести пример такой реализации?
Я до сих пор встречал только один случай, где массив наследников корректно удалялся через указатель на базу (здесь
Автор:
Дата: 30.11.05
), но там деструктор был виртуальный.
Любите книгу — источник знаний (с) М.Горький
Re: наследование, delete, утечка
От: alzt  
Дата: 23.10.08 08:29
Оценка:
Здравствуйте, dronord, Вы писали:

D>
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. Сделать деструктор класса А скрытым. Тогда код вообще перестанет компилироваться.

То, что вы привели — это неопределённое поведение. Худший случай — если у вас не будет утечек памяти и всё будет работать нормально. А потом при смене\обновлении компилятора или изменении каких-либо условий вы получите неожиданный сюрприз.
Re[2]: Я просто в шоке
От: dronord  
Дата: 23.10.08 10:53
Оценка:
B>Я просто в шоке — этот вопрос обсуждается практически каждый месяц, и все равно всегда находятся люди, гнотовые спорить по этому поводу

Забыл сказать, что перед тем, как создать тему, воспользовался поиском. Ничего не нашел.
Догадывался, что с этой проблемой много сталкивались.
Re[5]: Я просто в шоке
От: Erop Россия  
Дата: 23.10.08 12:08
Оценка:
Здравствуйте, Bell, Вы писали:

E>>Ну, если тебе плевать на UB, и деструкторы тривиальные, то удастся конечно, на большинстве реализаций...

E>>В этом смысле ситуация такая же, как с уалением одного объекта, без виртуального деструктора.

B>Можешь привести пример такой реализации?

B>Я до сих пор встречал только один случай, где массив наследников корректно удалялся через указатель на базу (здесь
Автор:
Дата: 30.11.05
), но там деструктор был виртуальный.


А что, есть реализации, где
struct S1 { char F1; }
struct S2 : S1 { char F1[100]; };
S1* p = new S2[100];
delete [] p;
работает некорректно?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Я просто в шоке
От: elcste  
Дата: 23.10.08 12:34
Оценка:
Здравствуйте, Erop, Вы писали:

E>А что, есть реализации, где
E>struct S1 { char F1; }
E>struct S2 : S1 { char F1[100]; };
E>S1* p = new S2[100];
E>delete [] p;
работает некорректно?


Собственно, я не знаю реализаций, где этот код откомпилируется. А по существу: да, есть, вот.
Re[7]: Я просто в шоке
От: Erop Россия  
Дата: 23.10.08 16:25
Оценка:
Здравствуйте, elcste, Вы писали:

E>Собственно, я не знаю реализаций, где этот код откомпилируется.

Ты про точку с запятой после struct S1 { char F1; }? Это скучно.

А по существу: да, есть, вот.
E>А по существу

Network Access Message: The website cannot be found

ссылка чего-то не работает.

Не расскажешь что там было написано.
На всяк. случай -- MSVC от 6 до 2003 вроде как кушают и не чихают...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Я просто в шоке
От: Bell Россия  
Дата: 24.10.08 06:28
Оценка:
Здравствуйте, Erop, Вы писали:

E>>>деструкторы тривиальные


E>А что, есть реализации, где
E>struct S1 { char F1; }
E>struct S2 : S1 { char F1[100]; };
E>S1* p = new S2[100];
E>delete [] p;
работает некорректно?


Осознал, согласен с "большинством реализаций"
Любите книгу — источник знаний (с) М.Горький
Re[8]: Я просто в шоке
От: elcste  
Дата: 24.10.08 08:55
Оценка:
Здравствуйте, Erop, Вы писали:

E>А по существу: да, есть, вот.

E>>А по существу

Network Access Message: The website cannot be found

ссылка чего-то не работает.

E>Не расскажешь что там было написано.

Да, сегодня лежит. Там on-line компилятор и виртуальная машина, которая диагностирует ошибку выполнения этого кода.

Виртуальная машина — вполне себе implementation (в понимании стандарта).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.