Конструктор и деструктор
Функцию или класс, который будет отвечать за создание экземпляров другого класса.
Ага, а для создания фабрик использовать фабрики фабрик и т.д.
Этого далеко не достаточно.
Так же нужно будет внимательно проследить за освобождением ресурсов (для этого лучше использовать smartpointer-ы), обернуть вызов конструктора в блог try/catch.
А как быть, если пользователь (по ошибке) создаст (попытается) объект в статической памяти?
Короче, способ имеет право на жизнь, но IMHO сопряжен с дополнительными проблемами.
Так же нужно будет внимательно проследить за освобождением ресурсов (для этого лучше использовать smartpointer-ы), обернуть вызов конструктора в блог try/catch.
А как быть, если пользователь (по ошибке) создаст (попытается) объект в статической памяти?
В дотнете такое решение будет работать достаточно неплохо. :) Правда, там это работает за счёт высокого уровня абстракции.
неуверен, что это хорошее решение. Это может быть приемлемым способом(если конечно, эта исключительная ситуация нормально обрабатывается), только тогда, когда программа знает как вести себя в этом случае. Например, если я разрабатываю к примеру игру, и получил исключение при инициализации класса
CResourceManager, то единственный выход - завершить всё, и написать соотв. запись в лог. Но, во многих случаях, возможно изменение поведения программы даст другой результат. И намного удобнее, обработку всяких таких ситуаций возложить на плечи отдельного класса, чем рассеивать по коду. Так, что по-моему уровень абстакции, здесь не особо влияет на элегантность решения.
Хотя, статических объектов в дельфине конечно нету..
Хотя, статических объектов в дельфине конечно нету..
Разница огромная. Или спроэктировать один класс нормально, или искать баги по всей программе.
Если фабрику, то все-равно ее ошибки нужно анализировать
Что-то очччень сомневаюсь...
Как можно вызывать деструктор несозданного объекта?
Деструкторы должны вызываться только для инициализированных полей класса, но не для всего класса.
А так можно делов таких натворить! Например, освободить память по неинициализированному указателю.
а try/catch/finally использовать необходимо всегда.
Кто тебе такое сказал?
Я вот наоборот стараюсь обходиться без них (см. недавнюю тему http://forum.codenet.ru/showthread.php?t=49265&page=5)
Какая разница, вернет тебе конструктор исключение или фабрика NULL,
Разница огромная.
Хотя бы потому, что NULL возвращается, а исключение выбрасывается (вызывается).
ситуация-то исключительная и обрабатывать ее по-любому надо..
Исключительная ситуация только с исключением, а с NULL - это вовсе не "исключительная ситуация"
Если фабрику, то все-равно ее ошибки нужно анализировать
Что значит "ее ошибки" ? И зачем их анализировать?
Не смогла (не захотела) фабрика создавать объект, - вернула NULL. Это не ошибка фабрики! Это результат (нулевой) её работы.
В принципе, ничего анализировать не надо. Кроме обычной проверки указателя на ненулевое значение, которое и так надо делать.
А вот с исключениями хорошо бы проанализировать: что за исключение, почему возникло.
Как можно вызывать деструктор несозданного объекта?
Такая вот интересная фигня в делфи. Там и поля объекта сразу проинициализированы - нулями.
"Сразу" не бывает. Тогда для чего конструктор, если все уже проинициализировано "сразу".
А если поле - не POD объект? Чем он "сразу" проинициализирован?
В любом случае вызывать деструктор невалидного объекта - это опасно.
Нулями, такими вот: 0x00. А разрушение недосозданного объекта действительно косяк в делфи. Одно из средств защиты - это использование метода Free, для разрушения объекта, он проверят на nil (NULL) значение Self указателя (this).
Да я ж не терминологию обсуждаю - я про то что в любом случае нужно будет вставить обработчик возникшей ошибки. Возникшей ошибки создания класса, которую вернет фабрика. Конечно же это не ошибка фабрики, но раз фабрика только для того и существует, можно обозвать это ее ошибкой :)
:D начинаю понимать почему спольского турнули из майкрософта!
Для тех кто пользуется компиляторами от майкрософт могу только сказать что в свое время дизассембрировав код трех майкрософтовских программ увидел что каждая функция у них начинаеся с "глобального" try (кавычки чтоб не было споров по поводу терминологии :D). Конечно 3 программы от такого гиганта - капля в море, но все же их программисты (многие) - пишут так. Для своей системы на своих компиляторах. Даже драйвера. К сожалению про юниксы и маки ничего не скажу :( - подходы там разные. Кстати try/except ловит и ошибки ОС типа обращения по невыделеному адресу, но я думаю это все знают.
Можете глянуть на конструктор MFC::CFile, тот что с параметрами - честно предупреждают что вызывает исключение. Кстати расскажите, как с этим в .NET?
Да может и не косяк.. Код деструктора-то обычно небольшой, можно и на nil-ы проверить. Но документации по такому поведению я правда не видел! Хотя не скажу чтобы уж очень я ее читал : )
Ну а вообще для таких случаев люди обычно не парятся, а используют bool Init(). Пусть это не столь элегантно но.. работает
Представьте себе, что никто. Если нужно выделить память, то это делается проще. А именно создается специально метод Init(); для этой цели и метод Destroy(); для освобождения памяти. И объект получается очень даже гибко управляемым.
Да я ж не терминологию обсуждаю - я про то что в любом случае нужно будет вставить обработчик возникшей ошибки. Возникшей ошибки создания класса, которую вернет фабрика. Конечно же это не ошибка фабрики, но раз фабрика только для того и существует, можно обозвать это ее ошибкой :)
Единственная "ошибка", которую может вернуть фабрика - это ничего не вернуть. Вся обработка почему, как и зачем - описывается один раз в теле фабрики, а не каждый раз при попытке создания объекта вручную.
:D начинаю понимать почему спольского турнули из майкрософта!
Для тех кто пользуется компиляторами от майкрософт могу только сказать что в свое время дизассембрировав код трех майкрософтовских программ увидел что каждая функция у них начинаеся с "глобального" try (кавычки чтоб не было споров по поводу терминологии :D). Конечно 3 программы от такого гиганта - капля в море, но все же их программисты (многие) - пишут так. Для своей системы на своих компиляторах. Даже драйвера. К сожалению про юниксы и маки ничего не скажу :( - подходы там разные.
Флуд, и не относится к теме.
Да может и не косяк.. Код деструктора-то обычно небольшой, можно и на nil-ы проверить. Но документации по такому поведению я правда не видел! Хотя не скажу чтобы уж очень я ее читал : )
Обычно небольшой.. Это у вас он обычно небольшой. К тому же удалять невыделеный объект противоречит логике. И эта нелогичность добавляет геморра программисту.
Ну а вообще для таких случаев люди обычно не парятся, а используют bool Init(). Пусть это не столь элегантно но.. работает
Да-да-да, это работает, и достаточно элегантно и управляемо.
Мда? А обрабатывать это ничего дядя будет? :D
Если у вас он слишком большой - вы прохо спроектировали класс, уважаемый
А никто и не говорил что удаляет невыделенные объекты, это про что?
Нет, не элегантно
Уважаемый, сходите в википедию и посмотрите значение сова флуд. Я вас очень прошу.. И слова оффтопик. И то что конструктор и деструктор это методы, они же функции, класса
Мы то инкапсуляцию не нарушаем, мы используем init().
Ну а вообще для таких случаев люди обычно не парятся, а используют bool Init(). Пусть это не столь элегантно но.. работает
Это нормально.
Нет, не элегантно
Факты?
Да я ж не терминологию обсуждаю - я про то что в любом случае нужно будет вставить обработчик возникшей ошибки. Возникшей ошибки создания класса, которую вернет фабрика. Конечно же это не ошибка фабрики, но раз фабрика только для того и существует, можно обозвать это ее ошибкой
Ты пытаешься использовать фабрику в своем варианте без нее с внешней обработкой ошибки. А зачем?
Возникшие при создании объекта проблемы фабрика и обработает. Внешний код лишь либо получает, либо не получает объект.
начинаю понимать почему спольского турнули из майкрософта!
А с чего ты взял, что его "турнули"? Факты, пожалуйста.
А ты до сих пор паботаешь в MS ? :)
Вместо Спольски?
P.S. Спольски, а не спольского. Кроме того иностранные фамилии не склоняются.
Для тех кто пользуется компиляторами от майкрософт могу только сказать что в свое время дизассембрировав код трех майкрософтовских программ увидел что каждая функция у них начинаеся с "глобального" try (кавычки чтоб не было споров по поводу терминологии :D). Конечно 3 программы от такого гиганта - капля в море, но все же их программисты (многие) - пишут так.
Для своей системы на своих компиляторах. Даже драйвера.
Ну что сказать... дурацкий какой-то аргумент... ничем не подкрепленный... да ещё и не по теме...
Ну микроскопом ещё люди пользуются... но не везде... хотя в трех лабораториях, где я был, он был. :D
К сожалению про юниксы и маки ничего не скажу - подходы там разные.
К чему подходы разные? К чему тут вообще маки и юниксы?
Кстати try/except ловит и ошибки ОС типа обращения по невыделеному адресу, но я думаю это все знают.
Слава богу, что не все... Ты путаешь разные исключения: "языковые" и SEH.
Желательно в этом разбираться прежде, чем лезть в спор.
Можете глянуть на конструктор MFC::CFile, тот что с параметрами - честно предупреждают что вызывает исключение.
Ой, не знаю такой библиотеки... :)
Давай что-то более известное.
Да может и не косяк.. Код деструктора-то обычно небольшой, можно и на nil-ы проверить. Но документации по такому поведению я правда не видел! Хотя не скажу чтобы уж очень я ее читал
Да при чем тут размер кода деструктора и nil-ы ?
Косяк может и в одной строке уместиться преспокойно. И не обязательно твоего деструктора, а и деструктора родительского класса, или одного из полей твоего класса.
Вот это да. А я всегда думал, что проэктировать следует класс = сущность. Ах нет же, оказывается, он не может быть слишком большим. Вот незадача.
А никто и не говорил что удаляет невыделенные объекты, это про что?
про дельфи-подход.
Нет, не элегантно
А бросать исключения в конструкторах и потом их отлавливать значит по-вашему элегантней..
Уважаемый, сходите в википедию и посмотрите значение сова флуд. Я вас очень прошу.. И слова оффтопик. И то что конструктор и деструктор это методы, они же функции, класса
Уважаемый, сходил, посмотрел, и даже вам процитирую:
Флуд, или редко флад (от англ. flood /flʌd/ — «наводнение») — пустословие, сообщения в интернет-форумах и чатах, занимающие (во многих случаях) большие объёмы, либо наоборот — состоящие из одного слова или нескольких символов, и не несущие какой-либо новой, полезной или смысловой информации.
. Абсолютно уместное слово в данной ситуации.
Факты?
Ух не хотел до цитирований доходить.. : )
Использование функций типа set_date для инициализации объектов класса не элегантно и чревато ошибками. Так как нигде не утверждается, что объект должен быть инициализирован; программист может забыть сделать это или часто с равно плачевным результатом, сделать это дважды. Лучший подход состоит в том, чтобы позволить программисту объявить функцию явно предназначенную для инициализации объекта. Так как такая функция конструирует значения данного типа, он называется конструктором данного класса и опознается в языке благодаря тому, что имеет то же имя, что и сам класс.
Хотя, конечно, вы можете сказать что Страуструп для вас не авторитет. Тут я не буду искать чем вам возразить..
Внешний код лишь либо получает, либо не получает объект.
:eek: .. Да я ж про то что все равно обработку во внешнем коде ставить надо - получил он этот объект или не получил. Нет, естественно простого сравнения достаточно и исключения не потребуются, но обработка все-равно будет! Вот если бы фабрика вообще избавляла от необходимости писать доп. код обработки ошибок, цены б ей не было.
А с чего ты взял, что его "турнули"? Факты, пожалуйста. А ты до сих пор паботаешь в MS ? : ) Вместо Спольски?
P.S. Спольски, а не спольского. Кроме того иностранные фамилии не склоняются.
Это была шутка (хотя иногда склонен так думать, читая его статьи/книгу). Там был смайлик. Нет, не везде где я ставлю смайлик я шучу :) Я там никогда не работал и врядли буду. Польская (вроде бы) фамилия, действительно в русском не склоняется, и я это знаю, я ее еще и с маленькой написал. Просто у меня двоякое отношение к этому автору (могу объяснить, но где-нить в Общалке - работал с его системами), поэтому я его так русифицировал. Смит, Бонд, Джонсон (например) склоняются, если пишутся по-русски.
ничем не подкрепленный
могу посоветовать хороший дизасм :)
К чему подходы разные? К чему тут вообще маки и юниксы?
Используются другие компиляторы, куча разработчиков (модулей системы) каждый из которых выражает свою точку зрения на написание кода в целом и инициализации классов в частности. А многие учатся по их исходным кодам (на кого же равняться как не на разработчиков системы для которой пишешь) и начинают делать так же. В винде майкрософтовцы имеют корпоративные стандарты написания кода и те небольшие обрывки которые нам удается видеть "стандартны".
Желательно в этом разбираться прежде, чем лезть в спор.
Вспомни как ловятся ошибки чтения/записи диска при использовании MMF.
Ой, не знаю такой библиотеки...
Давай что-то более известное.
Давай. Но я не знаю что знаешь ты : ) Давай TFileStream?
Да при чем тут размер кода деструктора и nil-ы ?
Ну это я hardcase написал. Про дельфи. Я незнаю, знаете ли вы что это такое :), но там в деструкторе _лучше_ проверять поля класса перед их уничтожением, если в констукторе возможен эксепшн
А бросать исключения в конструкторах и потом их отлавливать значит по-вашему элегантней..
Нисколько. Я не знаю ни одного элегантного метода обработки ошибок в тех языках которыми владею. Хотя.. в ассемблере все элегантно : ), ибо не отличишь одно от другого. Если знаете - подскажите, буду по гроб жизни благодарен, но чутье подсказывает мне что такого нет
не несущие какой-либо новой, полезной или смысловой информации
тоесть все что я говорю вы давно знали?
Для меня Мейерс является большим авторитетом, чем Страуструп. И вот, что он пишет:
Не позволяйте исключениям покидать деструкторы.
К тому же Страуструп был прав, и Мейерс прав в этом случае(и они не противоречат друг-другу), так как код получается чем-то вроди:
{
public:
example()
{
onInitError = Init();
}
int Init()
{
};
private:
int onInitError;
}
Как по мне - очень даже элегантное решение.
:eek: .. Да я ж про то что все равно обработку во внешнем коде ставить надо - получил он этот объект или не получил. Нет, естественно простого сравнения достаточно и исключения не потребуются, но обработка все-равно будет! Вот если бы фабрика вообще избавляла от необходимости писать доп. код обработки ошибок, цены б ей не было.
А если б она за вас еще б и код писала - то ваще ваще цены б ей не было. Фабрика нужна только для того, чтобы изменять поведение программы, в зависимости от полученой исключительной ситуации.
Это была шутка (хотя иногда склонен так думать, читая его статьи/книгу). Там был смайлик. Нет, не везде где я ставлю смайлик я шучу :) Я там никогда не работал и врядли буду. Польская (вроде бы) фамилия, действительно в русском не склоняется, и я это знаю, я ее еще и с маленькой написал. Просто у меня двоякое отношение к этому автору (могу объяснить, но где-нить в Общалке - работал с его системами), поэтому я его так русифицировал. Смит, Бонд, Джонсон (например) склоняются, если пишутся по-русски.
шутник, а еще обижаетесь, что я назвал эту "шутку" флудом..
Нисколько. Я не знаю ни одного элегантного метода обработки ошибок в тех языках которыми владею. Хотя.. в ассемблере все элегантно : ), ибо не отличишь одно от другого. Если знаете - подскажите, буду по гроб жизни благодарен, но чутье подсказывает мне что такого нет
смотрите выше. метод избавляет от кучи геморроя, а если классы управляются фабрикой - то это вообще сказка :)
тоесть все что я говорю вы давно знали?
А вы пока ничего сверхестественного и не сказали.
З.Ы. Уважаемый, а вы бы все-таки потрудились почитать разницу между обработкой исключений при помощи SEH и нативной(С++овой) обработкой. Для ленивых - даю ссылку: http://www.devdoc.ru/index.php/content/view/seh_vs_cpp.htm Да, в MSVC одно сделано через другое, но это в общем случае неверно.
Хотя, конечно, вы можете сказать что Страуструп для вас не авторитет. Тут я не буду искать чем вам возразить..
Ох как же ты любишь додумывать за других... "Страуструп для вас не авторитет", "Нарушаете принципы инкапсуляции..."
А ответ на твою цитату Страуструпа прост: в ней ничего не говорится про фабрику. А между тем, фабрика (фабрика объектов, фабричный метод) и может быть той явно предназначенной и не только для инициализации, но и для создания и проверки созданного объекта функцией. Кроме того фабрика может не просто создать и проанализировать объект, а сделать это по-разному в зависимости от условий. Поэтому она ещё иногда и называется "виртуальным конструктором".
Отсюда нет никакой неэлегантности вызова init(), впрочем, как и др. действий с объектом, из фабрики. Фабрика для того и служит, чтоб предоставить пользователю готовый, проинициализированный объект.
Более того фабрика может быть статическим методом того же класса, что и создаваемый ею объект. При этом даже без метода init() принцип инкапсуляции не нарушается.
И ещё, обычно при использовании фабрик, исключается возможность создания экземпляра "напрямую".
:eek: .. Да я ж про то что все равно обработку во внешнем коде ставить надо - получил он этот объект или не получил. Нет, естественно простого сравнения достаточно и исключения не потребуются, но обработка все-равно будет! Вот если бы фабрика вообще избавляла от необходимости писать доп. код обработки ошибок, цены б ей не было.
Ну так в чем проблема создать фабрику, которая обрабатывает ошибки создания?
И что значит "обработка все-равно будет"? Никакой дополнительной обработки может и не быть. Обычно при использовании указателей они проверяются на ненулевое значение независимо фабрикой ли был создан объект или обычным образом. Так вот этой проверки будет достаточно, ничего дополнительного можно не вводить.
Это была шутка (хотя иногда склонен так думать, читая его статьи/книгу).
Просто у меня двоякое отношение к этому автору (могу объяснить, но где-нить в Общалке - работал с его системами)
Вполне адекватный автор. Что именно ты прочел и что вызвало у тебя такую реакцию?
С какими системами работал? Можешь ответить в Общалке.
могу посоветовать хороший дизасм :)
При чем тут дизасм? "Я дизассемблировал ТРИ программы" - это не доказательство, да и доказательством чего это может быть?
Используются другие компиляторы, куча разработчиков (модулей системы) каждый из которых выражает свою точку зрения на написание кода в целом и инициализации классов в частности. А многие учатся по их исходным кодам (на кого же равняться как не на разработчиков системы для которой пишешь) и начинают делать так же. В винде майкрософтовцы имеют корпоративные стандарты написания кода и те небольшие обрывки которые нам удается видеть "стандартны".
При чем тут компиляторы?
Зачем равняться на разработчиков ОС? Я не против них, но почему ты считаешь их истиной в "первой инстанции" и что равняться надо именно на них?
Что касается стандартов, то код MS - это такая "солянка", что говорить о стилистике можно только в конкретной части кода. Да и к чему это ("глобальные" try) в данной теме?
Вспомни как ловятся ошибки чтения/записи диска при использовании MMF.
Да по разному они ловятся. Опять к чему это в данной теме?
Или ты будешь спорить, что исключения бывают разные?
В контексте топика имеются в виду исключения средствами языка, а ты съехал до SEH.
Давай. Но я не знаю что знаешь ты : ) Давай TFileStream?
Я знаю STL, к примеру.
Ну это я hardcase написал. Про дельфи. Я незнаю, знаете ли вы что это такое :), но там в деструкторе _лучше_ проверять поля класса перед их уничтожением, если в констукторе возможен эксепшн
И это фраза в защиту элегантности решения с исключением в конструкторе? :)
Ну, в делфи у объектов есть нехилый жизненный цикл. Чего стоит последовательность:
NewInstance (выделяем память под сам объект)
Constructor
AfterConstruction
...
BeforeDestruction
Destructor
Когда метод AfterContruction зовется ТОЛЬКО при удачном завершении конструктора, а в случае исключения в конструкторе автоматом зовется деструктор, но метод а BeforeDestruction не вызывается.
А для автоматической проверки на nil есть спец метод, о котором я говорил - Free. и вариация FreeAndNil (зовет Free и ставит указатель в nil). Потому деструкторы в делфи обычно последовательность вызовов процедуры FreeAndNil для внутренних объектов.
[quote=BCB Help]
Do not call AfterConstruction in application code.
[/quote]
Аналогично с Free() и прочими паскалевскими прибабахами
Согласен, правда не делаю между ними сравнений.
Получается, что мы не сможем сделать функцию init() виртуальной? А хотелось бы. Эх нету Мейерса под рукой, дома поконсультируюсь у него :)
Стирала б, убирала и готовила, тогда б я вообще этого поста б не оставил :) Боюсь вот это уж точно оффтопик (мой)
ну вы бОльший кусок к флуду отнесли, вот я и приобидился
И не собирался : ). Но по классификации флуда получается что или мой пост "баян", или абсолютно бесполезен, или бессмысленен. Я думаю это автору топика решать?
Да это я сказал про обработку ошибок вообще, невозможность создания объекта лишь их подмножество
Не додумывать, а думать. Между прочим помогает за рулем, да и вообще в любом управлении (людьми, машинами, процессами). Развивает мозг, позволяет предсказывать/предугадывать ситуации. В программировании тоже оказывает немалое подспорье.
Вот это действительно красиво и так сделано в Delphi, но мы налетаем на ограничения невозможности создать объект статически, за что я так люблю C++. И получается что конструктор класса-то - фактически не нужен?!
Ура, я как раз про это. Про то что либо придется писать try..except (это Delphi) / либо if <>nil then begin, какой бы способ (фабрику или эксепшн) ты не использовал. Но try/except в создающей функции способен предохранить тебя от огромного количества ошибок сверх этой невозможности создать объект
foxbugs. Накатаю постик на будущей недельке
Не надо так выделять мое "три". Я исследовал гораздо больше программ за свою жизнь, а эти были в одно время, все от майкрософт, и все рассматривались на предмет обработки ошибок/исключений. И я ничего не пытаюсь никому доказать, зачем мне это? Просто у всякой проблемы есть несколько способов решения и я разбираю один, а вы другой. В дискуссии мы выясняем достоинства и недостатки каждого из них, не так ли? А призыв поголовно использовать исключения или фабрики классов звучит подобно призыву верить в одного бога и, на мой взляд, неприемлем
Я не говорю что надо, я говорю как происходит. Я не считаю их истиной в последней инстанции но уверен что их код создан максимально эффективно отработать на их платформе. "Глобальные" try - к тому что микрософт ими не брезгует, и что если кому-то покажется некрасивым/неэффективным/нелогичным использование исключений, пусть возьмут на заметку
Не съехал а напомнил что и он в них входит, что прибавляет им весомости
Тогда глянь кто вызывает std::exception, у меня исходников STL нет под рукой.. И не думаю что STL использует фабрики классов
Не надо воспринимать мое "Пусть это не столь элегантно" как "Я вот вызвал бы исключение - это элегантно, а init() - совсем наоборот". Я про то что не надо париться если это покажется некрасивым
Да просто бывает я память GetMem-ом выделяю, ну и проверяю в конце if Assigned() или if <> nil then FreeMem. Объекты-то конечно Free(AndNil)
Получается, что мы не сможем сделать функцию init() виртуальной? А хотелось бы. Эх нету Мейерса под рукой, дома поконсультируюсь у него :)
Конечно не сможем. Да и зачем? Если она нужна только(!!) для создания объекта.
Да, Init стоит делать виртуальным. Опыт подсказывает, что сильно это удобно.
Ну, специфика неуправляемого (unmanaged) кода. Я вот уже и забыл совсем, что такое "выделение памяти руками" и вызов деструктора. Вообще, выделение памятии маллоками или гетмамами хреновая практика - уж лучше динамические массивы.
А если мы наследника сделаем?
Куда лучше, в плане удобства, да только специфика программы такая что эффективнее делать так. То что GemMem выделяется, конечно, это я загнул - можно и динамическими, а вот то что VirtualAlloc уже никак :( Хотя бывает что и GetMem никак..
ПыСы.
Чуть ли не с первого поста забываю сказать что мы у человека компилятор и ось не спросили :)