green IMHO по любому косяк. И какая штатная работа когда сработало исключение? Разница только в том, что память под объект выделяется снаружи функции, конструктор внутри, деструктор и уничтожение памяти снаружи. Но и здесь пока проблемы не вижу. Так как деструктор в catch тоже должен сработать. Пока не вижу проблемы даже при оптимизации компилятором, не говоря уже о явной передачи ссылки.
Ustus Боюсь, не понял. Можешь объяснить? Booster Ну и что? Исключение-то обрабатывается. Почему? Объект вне блока try.
green Ну что-что вне, всё равно при выходе из блока и при срабатывании исключения деструкторы автоматических объектов вызываются. А если try нету она всё равно выйдет из текущего блока, вызовется деструктор и работать по любому с объектом будет нельзя. А почему объект вне try? Код (Text): try { ClassType t = foo(); } Код (Text): try { ClassType t ; foo(&t); }
Booster чего-то не понял ты хочешь сказать, что в коде Код (Text): void Test() { Array a; try { a = ConstructArray(0, 10); } catch(...) { } // 1111 foo(a); } где 1111 объект а будет разрушен?
Booster Дык говорю же - объект вне блока try, поэтому деструктор в catch не сработает. А вообще, конечно, сработает - при выходе из блока, в котором определён объект а, т.е. из ф-ции Test. Таким образом, после catch можно работать с а. --- Потому, что есть разница между Код (Text): Array a; try { a = ... } и Код (Text): try { Array a; а = ... }
RedLord Да я не про то. Если мы делаем явную ссылку, то что написал ты не имеет смысла. Уж если у нас конструктор вызывает исключения, то удалиться он конечно при выходе из основного блока, но и работать дальше с ним вполне можно, так как мы сами задали такую реализацию, объект то всё равно сконструированный есть. А если мы используем оптимизацию компилятора то. Код (Text): try { ClassType t = foo(); } преобразуется в. Код (Text): try { ClassType t ; foo(&t); } Не надо мешать оптимизацию компилятора и явное задание ссылки. green Да что-то я совсем забыл, что можно ещё и: Код (Text): ClassType t; try { t = foo(); } использовать с оптимизацией компилятора. Да согласен, тут возможен большой косяк с оптимизацией.
green Ммм... трудновато будет в двух словах... Примерно так: в любом месте, где возможно использование объекта функциями, не относящимися к его реализации - данные объекта должны быть достоверны. Это даже не ООП, это еще в модульном программировании было. Так что надо или доводить операцию до конца, или предусмотреть возможность отката. Простейший пример (правда совсем не из этой области - транзакции в БД). Да, п.1 никуда не делся, но объект останется корректным. И вообще не понимаю, почему этот пункт тебя смущает. Меня больше смущают public-данные - это почти всегда признак плохого стиля. Большиство таких проблем оттого, что С++, несмотря на все его ООП все еще остается языком достаточно низкого уровня, чтобы позволять такие штуки. Но тут уже выбирай - или придерживаешься правил, или разгребаешь последствия. У меня под боком код лежит - просто пЭсня. Чего стоит например создание массива структур, а потом - использование его через преобразование его адреса к char* и дальнейшей побайтной работы. Причем после вычисления адреса (я не в силах описать этот феерический процесс) он преобразуется опять к указателю на структуру и т.д. Все это щедро разбавлено ассемблерными вставками. У меня много всторостепенных вопросов и два главных: что курил автор сего и где взять такой дури? 8-[ ] Сорри за оффтоп, наболело...
Booster посмотри внимательно код green - Код (Text): struct Array { Array() : cValidData_(0){} int data_[MAX_ARRAY]; int cValidData_; }; где конструктор вызывающий исключения? ConstructArray - вызывает исключения.
Ustus А... то есть любая доступная операция с объектом не должна оставлять объект в несогласованном состоянии. Ну да, в принципе согласен. Ты только не забывай, что это пример, а не кусок кода из реального проекта. И разбавлять его не относящимися к делу конструкциями не следует, imho. Ну как это - почему? Программа ведь должна быть алгоритмически независима от оптимизаций компилятора.
Ustus Очень даже смущает. Как я понимаю эта оптимизация не должна влиять на логику. А тут у нас деструктор вызывается только при выходе из верхнего блока, файл например может остаться заблокированным, а мы этого ни никак не ждали. RedLord Да согласен, дело не в конструкторе, а в: green Вообщем всем сенкс, теперь стало ясно.
green Booster Логично. Но на практике это не единственный случай, хотя с ходу не решусь назвать примеры. Но конструкторы\деструкторы - это вообще очень тонкая область. Например не стоит закладывать в конструкторы всякие сторонние глобальные эффекты, поскольку не всегда можно предсказать место и количество вызовов конструкторов, простейший пример на форуме уже рассматривали: A a = A(1); - для не особо оптимизирующего компилятора допустимо два вызова конструктора, хотя многие даже с минимальной оптимизацией обходятся одним. Но вообще я слабо представляю, где может появится у вменяемого человека такой код, как в примере. Хотя видел и не такое 8-) P.S. Кстати, насчет кривости компиляторов - кто может посмотреть GCC поновее? А то в той версии, что мимо меня проходила (не помню точно) некорректно (ИМХО) раскручивается стек при вызове исключения из деструктора - не все деструкторы вызываются.
TO: RedLord >>а исключения должны покидать деструктор? Покурите Скотт Мэйерс "Эффективное использование С++", какое издание сейчас последнее не знаю. Там про ваш вопрос написано да и про многие другие вопросы.
Похоже что это только разрешение, а не жёсткое утверждение. А оптимизация майкрософтского компилятора в отношении возможного возвращения нескольких объектов, вообще полуандок. Ustus К сожалению видимо это очень верно. Но всё таки жаль, ведь конструктор по идее очень удобное место для инициализации, а тут приходиться использовать всякие Init для сложных ресурсов. Как то всё это не ООП.