Osnova
>Некоторые переоценивают роль виртуального деструктора
А потом начинается такое: http://www.gamedev.ru/code/forum/?id=58296
Osnova
>Ну и прочее и прочее и прочее.
Выпендрился? А то что автор темы на равном месте может словить утечку памяти и порчу хипа, это как?
> Видите, насколько я круче вас в деструкторах шарю? :)
Расскажи нам тогда про виртуальные конструкторы.
> Реально ли такое:
Это невозможно.
RadicalEd
Хм? Он уже сам в посте #6 написал, как это сделать.
И сделал
чем плох такой вариант?
class RefObject { public: RefObject(){refCount=1;}; virtual ~RefObject(){}; AddRef(){refCount++;}; Release(){refCount--; if (refCount==0) delete this;}; private: int refCount; } class A:public RefObject { public: /*some code*/ virtual ~A(){}; virtual void Render()=0; /*some code*/ } class B:public A { public: /*some code*/ virtual ~B(){/*some code*/}; virtual void Render(){/*some code*/} /*some code*/ } class C:public A { /*some code*/ virtual ~C(){/*some code*/} virtual void Render(){/*some code*/} /*some code*/ } class D { ~D(){/*пробегаем и релизим все объекты, очищаем вектор+прочие работы*/} void Add(A* obj){obj->AddRef();renderObjects.push_back(obj);} /*some code*/ void Render() { /*some code*/ for (std::vector<A*>::iterator iter=renderObjects.begin();iter!=renderObjects.end();iter++) { (*iter)->Render(); } /*some code*/ } std::vector<A*> renderObjects; } void main () { /*some code*/ D d; B* b1=new B(); B* b2=new B(); C* c1=new C(); C* c2=new C(); d.add (b1); d.add (b2); d.add (c1); d.add (c2); d.Render(); b1->Release(); b2->Release(); c1->Release(); c2->Release(); /*some code*/ }
пример примитивный, но тут лишь мысль
du_hast
> produce undefined behaviour. On many implementations, the destructor for B will
> not be called in this situation.
Может быть в данном случае undefined behaviour - самое страшное что несет - это что не будет вызываться деструктор B (иначе он даже будет вызываться). Чтобы например на C++ вместо не-вызова деструктора был скажем выброс исключения, надо отслеживать типы в динамике - а это ведь не делается.
Обычно UD надо бояться, но (мне кажется) не в этом случае.
В любом случае это уже за пунктом 3.
Wraith
> Вроде бы даже удаление потомков с нетривиальным деструктором (12.4[3], 12.4[4])
> по указателю на предка без виртуального деструктора - это UB (5.3.5[3]) .
Так я и не говорил про потомков с нетривиальным деструктором. Только с пустым.
Другое дело что в Википедии говорится про UB даже если деструктор ... эээ... не пустой?
Погодите, но ведь в примере из Википедии деструктор-то не пустой!!! Т.е. оно подходит под пункт 5.3.5[3].
Мои же рассуждения под него не подходят. В них деструктора нет. (Или он пустой).
> И кстати, что означают фразы "инвариантно пустой" и "тождественно пустой"?
Ну пустой при любом перепроектировании системы и сейчас, и в любой ее последующей версии.
red noise
> Есть простое правило - при наследовании деструкторы должны быть виртуальными
> всегда.
Ну какое правило!! У-у-у-у!!!
Казалось бы - зачем тогда не делать этого автоматически, компилятору? Почему мы вообще должны писать ключевое слово virtual для деструкторов и не сделать их "всегда виртуальными"? Ведь Страус этого не сделал.
sildc
> пример примитивный, но тут лишь мысль
А ещё лучше smart_pointer
чтобы сам делал release при при присваивании и в деструкторе
>это что не будет вызываться деструктор B
Да нет же. Откуда эту глупость взяли. Обычная ситуация - креш. С++ объект вообще говоря ничего не знает про свой настоящий адрес, где начинается оталлоцированная память.
struct A { int a; }; struct B { int b; }; struct C : public A, public B { int c; }; int main() { B *b = new C; delete b; return 0; }
Osnova
> Так я и не говорил про потомков с нетривиальным деструктором. Только с пустым.
Так вот я и объясняю, что даже пустой деструктор, если он нетривиальный, - уже мемлик тебе обеспечен.
Wikipedia
> Объе́ктно-ориенти́рованное программи́рование (ООП) — парадигма программирования,
> в которой основными концепциями являются понятия объектов и классов.
Блин, а как же там Инкапсуляция, Наследование, Полиморфизм?
Википедия жжот.
Osnova
Я считаю, зря не сделал :) Люди имеют с этого только проблемы, + еще одно правило для запоминания.
Что за глупости с виртуальностью?!
Есть простые правила:
1. Если в Вашем классе есть ХОТЯ БЫ ОДИН виртуальный метод, то ОБЯЗАТЕЛЬНО деструктор должен быть виртуальным (чтобы удалить помимо объекта ещё и созданную виртуальную таблицу с указателями на виртуальные методы класса).
2. Если у базового класса есть наследники, то это НЕ ЗНАЧИТ что деструктор должен быть виртуальным. Понял свою ошибку :)
3. Если у Вас складывается ситуация, когда в базовом классе есть переопределённые (перегруженные) методы и есть классы наследники, в которых происходит замещение этих методов, то без виртуальности не обойтись, т.к. иначе будет сокрытие части методов в производном классе.
В Вашей реализации я вижу единственный метод Render() и делать его виртуальным нет никакого смысла, в производных классах просто замещайте его и всё (если Render() одинаков во всех производных классах, то его и замещать то не понадобиться. Помните, что объект производного класса состоит на некоторую часть из базового). Не нужно применять виртуальность там, где в этом нет необходимости, иначе это говнокод получается. Ведь виртуальность в ООП это не просто "волшебство" это ещё и пожиратель ресурсов. :)
TAB
А об этом, что скажень?
class A { A() { ... } ~A( ) { ... } }; class B : public A { B( ) { ... } ~B( ) { ... } }; ... ... A *a = new B( ); delete a;
Ведь, в этом случае деструктор B не будет выполнен, понимаешь какая это бомба?
Тема в архиве.