A>>В языке программирования C++ деструктор полиморфного базового класса должен объявляться виртуальным.
A>>Только так обеспечивается корректное разрушение объекта производного класса через указатель на соответствующий базовый класс.
A>>это же чушь.
R>Это высказывание является прямым следствием из 5.3.5/3.
struct A { virtual f(); ~A(); };
struct B:A { f(); };
int main()
{
B b;
A* pa = &b;
pa->f(); //полиморфный!
}
Здесь В замечательно обходится без виртуального деструктора и все корректно уничтожается, а 5.3.5/3 идет по градиенту.
А>>Какие могут быть ситуации, когда не вызывается дестуктор(сделал new и не сделал delete не в счет)?
V>Классический пример — отсутствие виртуального деструктора — http://cpp-reference.ru/articles/virtual-destructor/
В языке программирования C++ деструктор полиморфного базового класса должен объявляться виртуальным.
Только так обеспечивается корректное разрушение объекта производного класса через указатель на соответствующий базовый класс.
Технически никому он ничего не должен, особенно если:
1. он protected
2. delete вызывается не на Base*, хотя хранится именно Base* (например deleter в shared_ptr знающий правильный тип, хотя хранится Base*)
3. как показано выше — объект может быть локальным
Но, ссылка выше это же rule of thumb для новичков?
Здравствуйте, jazzer, Вы писали:
J>int main() J>{ J> B b; J> A* pa = &b; pa->>f(); //полиморфный! J>} J>[/ccode] J>Здесь В замечательно обходится без виртуального деструктора и все корректно уничтожается, а 5.3.5/3 идет по градиенту.
разрушение объекта производного класса через указатель на соответствующий базовый класс
Здравствуйте, Evgeny.Panasyuk, Вы писали:
А>>>Какие могут быть ситуации, когда не вызывается дестуктор(сделал new и не сделал delete не в счет)?
V>>Классический пример — отсутствие виртуального деструктора — http://cpp-reference.ru/articles/virtual-destructor/
EP>
EP>В языке программирования C++ деструктор полиморфного базового класса должен объявляться виртуальным.
EP>Только так обеспечивается корректное разрушение объекта производного класса через указатель на соответствующий базовый класс.
EP>Технически никому он ничего не должен, особенно если: EP>1. он protected
тогда не получится "удалять через указатель на базовый класс" EP>2. delete вызывается не на Base*, хотя хранится именно Base* (например deleter в shared_ptr знающий правильный тип, хотя хранится Base*)
там нет "удаления через указатель на базовый класс" — сначала указателю делается статик-каст к фактическому типу EP>3. как показано выше — объект может быть локальным
там тоже нет "удаления через указатель на базовый класс"
EP>Но, ссылка выше это же rule of thumb для новичков?
это да
но и пятница же
Здравствуйте, sts, Вы писали:
sts>тогда не получится "удалять через указатель на базовый класс"
sts>там нет "удаления через указатель на базовый класс" — сначала указателю делается статик-каст к фактическому типу
sts>там тоже нет "удаления через указатель на базовый класс"
это же ответ на:
В языке программирования C++ деструктор полиморфного базового класса должен объявляться виртуальным.
которое стоит самым первым предложением.
По аналогии можно сказать:
На планете Земля, все люди должны носить шлем. Только так обеспечивается защита головы при падениях с мотоцикла.
EP>>Но, ссылка выше это же rule of thumb для новичков? sts>это да sts>но и пятница же
Здравствуйте, Аноним, Вы писали:
А>Помогите новичку! А>Какие могут быть ситуации, когда не вызывается дестуктор(сделал new и не сделал delete не в счет)?
Удаление неполного класса — одни из самых неприятных плюсовых граблей.
Тоже деструктор pImpl не будет вызван.
Лечится через unique_ptr (который не даст удалить неполный тип) и добавление ~Owner() туда, где Impl уже определен.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, rg45, Вы писали:
A>>>
A>>>В языке программирования C++ деструктор полиморфного базового класса должен объявляться виртуальным.
A>>>Только так обеспечивается корректное разрушение объекта производного класса через указатель на соответствующий базовый класс.
A>>>это же чушь.
R>>Это высказывание является прямым следствием из 5.3.5/3.
J>
J>struct A { virtual f(); ~A(); };
J>struct B:A { f(); };
J>int main()
J>{
J> B b;
J> A* pa = &b;
pa->>f(); //полиморфный!
J>}
J>
J>Здесь В замечательно обходится без виртуального деструктора и все корректно уничтожается, а 5.3.5/3 идет по градиенту.
Где в этом примере (цитирую) "разрушение объекта производного класса через указатель на соответствующий базовый класс" о котором шла речь выше?
Да, к сожалению, авторы статьи не дали четкого определения, что они понимают под полиморфным классом. Из общего контекста статьи можно догадаться, что они вкладывали в это понятие более широкий смысл — класс, объекты которого могут не только использоваться, но и удаляться через указатель базового класса (именно этому вопросу в статье уделено много внимания). Конечно же, это недочет, неточность формулировки, но еще не повод разбрасываться ярлыками типа "чушь" и "говносайт".
--
Справедливость выше закона. А человечность выше справедливости.
V>Это все понятно. Полагаю, вы слишком формально подходите к статье, и вас смутило слово 'должен'. Но по сути, описано хорошее правило делать деструктор виртуальным в случае полиморфных типов. Можно использовать обычный деструктор, если вы точно уверены, как именно ваша иерархия классов будет использоваться или в целях оптимизации.
хорошее правило — это 'не делать того что не нужно делать' или 'делать только то что нужно делать'.
если виртуальный деструктор не нужен, то незачем его делать.
Здравствуйте, Abyx, Вы писали:
A>это не может быть следствием, т.к. `delete pointer-to-base-type;` это не единственный способ корректно разрушить объект через указатель на его базовый класс.
Вероятно, ты имеешь ввиду технику, подобную той, которая применяется в shared_ptr? Ну так в ней разрушение объекта производится как раз через указатель most derived класса (при правильно использовании, при неправильном можно получить все то же UB). При этом сам shared_ptr я бы рассматривал не как способ разрушения объекта, а как средство абстрагирования от деталей этого процесса.
Или ты что-то другое имеешь в виду? Ну тогда поделись, как еще можно разрушить объект через указатель на его базовый класс.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
A>>это не может быть следствием, т.к. `delete pointer-to-base-type;` это не единственный способ корректно разрушить объект через указатель на его базовый класс.
R>Вероятно, ты имеешь ввиду технику, подобную той, которая применяется в shared_ptr? Ну так в ней разрушение объекта производится как раз через указатель most derived класса (при правильно использовании, при неправильном можно получить все то же UB). При этом сам shared_ptr я бы рассматривал не как способ разрушения объекта, а как средство абстрагирования от деталей этого процесса.
R>Или ты что-то другое имеешь в виду? Ну тогда поделись, как еще можно разрушить объект через указатель на его базовый класс.
да, удалять объект можно с помощью deleter'а с type-erasure как у shared_ptr,
причем *внезапно* shared_ptr<BaseClass> это *указатель* на базовый класс.
еще объект может владеть сам собой (встроенный счетчик ссылок и delete this, как например в COM),
объект может удалять какой-то GC (напр. Arena GC), впрочем это опять же deleter.
A>>>>В языке программирования C++ деструктор полиморфного базового класса должен объявляться виртуальным.
A>>>>Только так обеспечивается корректное разрушение объекта производного класса через указатель на соответствующий базовый класс.
R>Да, к сожалению, авторы статьи не дали четкого определения, что они понимают под полиморфным классом. Из общего контекста статьи можно догадаться, что они вкладывали в это понятие более широкий смысл — класс, объекты которого могут не только использоваться, но и удаляться через указатель базового класса (именно этому вопросу в статье уделено много внимания). Конечно же, это недочет, неточность формулировки, но еще не повод разбрасываться ярлыками типа "чушь" и "говносайт".
вот поэтому статья и говно, раз там написана чушь наподобие "раз полиморфный — значит ДОЛЖЕН быть виртуальный деструктор".
про весь сайт я может погорячился, хотя раз там есть статья такого качества — наверное и весь сайт такой.
у термина "полиморфный (класс)" есть вполне конкретное определение.
то что на это определение наложено ограничение, что объекты потомков такого класса будут удаляться через delete — это называется "более узкий смысл".
EP>>В языке программирования C++ деструктор полиморфного базового класса должен объявляться виртуальным.
EP>>Только так обеспечивается корректное разрушение объекта производного класса через указатель на соответствующий базовый класс.
EP>>Технически никому он ничего не должен, особенно если: EP>>1. он protected sts>тогда не получится "удалять через указатель на базовый класс"
не подменяйте тему.
в цитате написано не "удалять", а разрушать.
это разные вещи.
Здравствуйте, sts, Вы писали:
sts>Удаление неполного класса — одни из самых неприятных плюсовых граблей. sts>Тоже деструктор pImpl не будет вызван. sts>Лечится через unique_ptr (который не даст удалить неполный тип) и добавление ~Owner() туда, где Impl уже определен.
лечится включением предупреждений в компиляторе.
In Zen We Trust
Re: Разрушение компа прежде, чем будет разрушен объект, покатит? ;)
Здравствуйте, Аноним, Вы писали:
А>Какие могут быть ситуации, когда не вызывается дестуктор(сделал new и не сделал delete не в счет)?
на пример, если объёкт создали на компе, установленном на борут ГЧ, достигшей цели
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Abyx, Вы писали:
A>>>это не может быть следствием, т.к. `delete pointer-to-base-type;` это не единственный способ корректно разрушить объект через указатель на его базовый класс.
R>>Вероятно, ты имеешь ввиду технику, подобную той, которая применяется в shared_ptr? Ну так в ней разрушение объекта производится как раз через указатель most derived класса (при правильно использовании, при неправильном можно получить все то же UB). При этом сам shared_ptr я бы рассматривал не как способ разрушения объекта, а как средство абстрагирования от деталей этого процесса.
R>>Или ты что-то другое имеешь в виду? Ну тогда поделись, как еще можно разрушить объект через указатель на его базовый класс.
A>да, удалять объект можно с помощью deleter'а с type-erasure как у shared_ptr, A>причем *внезапно* shared_ptr<BaseClass> это *указатель* на базовый класс.
A>еще объект может владеть сам собой (встроенный счетчик ссылок и delete this, как например в COM), A>объект может удалять какой-то GC (напр. Arena GC), впрочем это опять же deleter.
A>много в общем разных способов.
Я понимаю, о чем ты говоришь, более того, сам придерживаюсь примерно тех же взглядов, и уже писал ранее по данной теме: http://rsdn.ru/forum/cpp/4071405.1
. Как мне кажется, при изучении C++ вообще, и особенно таких вопросов как времени жизни объектов и владение, прежде чем приступать к вопросам дизайна и паттернам проектирования, нужно познакомиться с синтаксисом и базовыми концепциями C++ на несколько более низком уровне. Название сайта "C++ reference" несколько ввело меня в заблуждение — я подумал, что его авторы как раз и поставили перед собой задачу познакомить читателя с основами языка, поэтому и не удивился, что они достаточно узко рассматривают вопросы удаления объектов, не рассматривая других аспектов и возможных реализаций владения. Хотя, могли бы, с учетом того, что паттернам они таки уделяют некоторое внимание.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>Здравствуйте, jazzer, Вы писали:
J>>Здравствуйте, rg45, Вы писали:
A>>>>
A>>>>В языке программирования C++ деструктор полиморфного базового класса должен объявляться виртуальным.
A>>>>Только так обеспечивается корректное разрушение объекта производного класса через указатель на соответствующий базовый класс.
A>>>>это же чушь.
R>>>Это высказывание является прямым следствием из 5.3.5/3.
J>>
J>>struct A { virtual f(); ~A(); };
J>>struct B:A { f(); };
J>>int main()
J>>{
J>> B b;
J>> A* pa = &b;
pa->>>f(); //полиморфный!
J>>}
J>>
J>>Здесь В замечательно обходится без виртуального деструктора и все корректно уничтожается, а 5.3.5/3 идет по градиенту.
R>Где в этом примере (цитирую) "разрушение объекта производного класса через указатель на соответствующий базовый класс" о котором шла речь выше?
Нету, в том-то и дело. Полиморфное использование есть, а полиморфного удаления нету.
R>Да, к сожалению, авторы статьи не дали четкого определения, что они понимают под полиморфным классом. Из общего контекста статьи можно догадаться, что они вкладывали в это понятие более широкий смысл — класс, объекты которого могут не только использоваться, но и удаляться через указатель базового класса (именно этому вопросу в статье уделено много внимания). Конечно же, это недочет, неточность формулировки, но еще не повод разбрасываться ярлыками типа "чушь" и "говносайт".
Ну, я конкретно не разбрасывался, но заявления типа "В языке программирования C++ деструктор полиморфного базового класса должен объявляться виртуальным." и "Cуществует правило — если базовый класс предназначен для полиморфного использования, то его деструктор должен объявляться виртуальным." являются слишком смелым обобщением, годным разве что для совсем начинающих, чтоб не отстрелили себе что-нть.
Правильная формулировка была бы такой: "если базовый класс предназначен для полиморфного использования удаления, то его деструктор должен объявляться виртуальным. Т.е. если ты не собираешься удалять объекты по голому указателю на базовый класс — нет необходимости делать деструктор виртуальным.
Например, есть у тебя std::map< std::string, std::shared_ptr<А> > — так вот в такую мапу ты вполне можешь запихивать указатели на В, и все будет правильно удаляться безо всяких виртуальных деструкторов (есть такое свойство у shared_ptr — deleter внутри него инициализируется в самом начале, и поэтому он знает, какой класс надо удалять).
Здравствуйте, Abyx, Вы писали:
A>Здравствуйте, sts, Вы писали:
sts>>Удаление неполного класса — одни из самых неприятных плюсовых граблей. sts>>Тоже деструктор pImpl не будет вызван. sts>>Лечится через unique_ptr (который не даст удалить неполный тип) и добавление ~Owner() туда, где Impl уже определен.
A>лечится включением предупреждений в компиляторе.
что лечится ?
если включить предупреждения, то деструктор вызовется ?
не верю
Re[2]: Разрушение компа прежде, чем будет разрушен объект, покатит? ;)
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Аноним, Вы писали:
А>>Какие могут быть ситуации, когда не вызывается дестуктор(сделал new и не сделал delete не в счет)?
E>на пример, если объёкт создали на компе, установленном на борут ГЧ, достигшей цели
так ведь и delete не успели сделатьт, так что это не в счет
Re[3]: Разрушение компа прежде, чем будет разрушен объект, покатит? ;)
Здравствуйте, sts, Вы писали:
А>>>Какие могут быть ситуации, когда не вызывается дестуктор(сделал new и не сделал delete не в счет)?
E>>на пример, если объёкт создали на компе, установленном на борут ГЧ, достигшей цели
sts>так ведь и delete не успели сделатьт, так что это не в счет
Ты ТС или просто рассуждаешь?
Я так понял, что ТС спросил, когда может так получится, что у созхданного С++ объекта не будет вызван деструктор. при этом случай с забытым delete, он считал тривиальным и просил на него не отвлекаться. на этот вопрос я и ответил...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском