Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.144.187.103] |
|
Страницы: (3) [1] 2 3 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Я, конечно, помню, что исключения в деструкторах --- это плохо, но всякое ж бывает (возможно, кроме этого, я что-то неправильно написал в C++ коде):
#include <iostream> #include <stdexcept> using namespace std; class Resource { private: string _name; bool _exn; public: Resource(string name, bool exn) { _exn = exn; _name = name; cout << "Open " << _name << endl; } virtual ~Resource() { cout << "Close " << _name << endl; if (_exn) throw runtime_error("EXCEPTION: " + _name); } }; void test() { Resource a("A", false); Resource b("B", true); cout << "test" << endl; } int main() { try { test(); } catch (runtime_error& e) { cout << "CATCH: " << e.what() << endl; } return 0; } stdout: Open A Open B test Close B stderr: terminate called after throwing an instance of 'std::runtime_error' what(): EXCEPTION: B --- http://ideone.com/zH6e0Q Golang: package main import "fmt" type Resource struct { name string exn bool } func OpenResource(name string, exn bool) (*Resource, error) { r := &Resource{name, exn} fmt.Println("Open", name) return r, nil } func (r *Resource) Close() error { fmt.Println("Close", r.name) if r.exn { panic("EXCEPTION: Close " + r.name) } return nil } func test() error { a, err := OpenResource("A", false) if err != nil { return err } defer a.Close() b, err := OpenResource("B", true) if err != nil { return err } defer b.Close() fmt.Println("test") return nil } func main() { defer rec() test() } func rec() { if r := recover(); r != nil { fmt.Println("CATCH:", r) } } stdout: Open A Open B test Close B Close A CATCH: EXCEPTION: Close B --- http://play.golang.org/p/bG-YnPIGX0 |
Сообщ.
#2
,
|
|
|
korvin, видимо, понимаешь не до конца. В деструкторах не должно быть исключений. Совсем.
Добавлено Ну и да, код не аналогичен Для аналога того, что написано в Go, тебе нужно реализовать defer(в виде некоторого guard'а), в котором дергать метод close ресурса. |
Сообщ.
#3
,
|
|
|
Цитата D_KEY @ korvin, видимо, понимаешь не до конца. В деструкторах не должно быть исключений. Совсем. Но если там довольно сложная логика освобождения ресурса, оно, тем не менее, может произойти, из-за какой-нибудь вызываемой библиотечной функции или аппаратной ошибки, 100% гарантии нет, или как? Цитата D_KEY @ Ну и да, код не аналогичен Для аналога того, что написано в Go, тебе нужно реализовать defer(в виде некоторого guard'а), в котором дергать метод close ресурса. Может и не аналогичен, но, пусть это чуть разные механизмы, но они используются для одной и той же цели и с более-менее схожим смыслом. Раньше это не мешало сравнивать RAII и try/catch/finally например. =) Кстати, как раз недавно наткнулся на реализацию чего-то подобного defer (точнее, документ опубликован ещё до выхода бета-версий Go, так что правильней наоборот, да и вообще, но не суть). Правда там для Java, но всё же. |
Сообщ.
#4
,
|
|
|
С этим кодом всё в порядке. В смысле, он, конечно, говнокод, но работать должен, как задумывалось. Что там с вашим g++14, не знаю, а вот Студия, Интел Компилер и g++11:
Open A Open B test Close B Close A CATCH: EXCEPTION: B Языком не допускаются только такая ситуация, в которой исключение бросается в тот момент, когда предыдущее ещё не поймано. Потому что если возникает такая ситуация, то эти два исключения невозможно однозначно отсортировать для обработки. Это может произойти только в тот момент, когда на пути от throw до catch выполниться ещё один throw, а это возможно только в деструкторе объекта, лежащего на разматываемой области стека. Т.к. заранее нельзя знать, по какой причине деструктор вызван, поэтому и нельзя допускать исключений, покидающих деструктор от слова вообще. |
Сообщ.
#5
,
|
|
|
Цитата korvin @ Я, конечно, помню, что исключения в деструкторах --- это плохо, но всякое ж бывает (возможно, кроме этого, я что-то неправильно написал в C++ коде) Просто современный компилятор юзаешь. virtual ~Resource() noexcept(false) { Цитата Qraizer @ а вот Студия, Интел Компилер Это ожидаемо. Цитата Qraizer @ g++11 А это был баг в 4.7 |
Сообщ.
#6
,
|
|
|
Да ну? Ну посмотри в "15.5.1 The std::terminate() function". Там нет ни одного упоминания исключения в деструкторе без дополнительного специального условия:
Цитата Так что да, вполне ожидаемо отсутствие исключения в приведённом выше коде. А что там у вас в C++14 за баги, я не в курсе. 1 In some situations exception handling must be abandoned for less subtle error handling techniques. [ Note: These situations are: —end example ] |
Сообщ.
#7
,
|
|
|
Цитата korvin @ Цитата D_KEY @ korvin, видимо, понимаешь не до конца. В деструкторах не должно быть исключений. Совсем. Но если там довольно сложная логика освобождения ресурса, оно, тем не менее, может произойти, из-за какой-нибудь вызываемой библиотечной функции или аппаратной ошибки, 100% гарантии нет, или как? Если есть опасения, значит отлавливай исключения в деструкторе. |
Сообщ.
#8
,
|
|
|
Зато есть
Цитата 15.2 Constructors and destructors 3 The process of calling destructors for automatic objects constructed on the path from a try block to a throw-expression is called “stack unwinding.” If a destructor called during stack unwinding exits with an exception, std::terminate is called (15.5.1). [ Note: So destructors should generally catch exceptions and not let them propagate out of the destructor. —end note ] Добавлено Ага. А ещё есть Цитата 15.4 Exception specifications так что формально деструктор без явной спецификации исключений считается nothrow. Как интересно. 15 A deallocation function (3.7.4.2) with no explicit exception-specification is treated as if it were specified with noexcept(true). |
Сообщ.
#9
,
|
|
|
Цитата Qraizer @ Да ну? Ну да. Цитата Qraizer @ Ну посмотри в "15.5.1 The std::terminate() function" А нахрена мне туда смотреть. Ещё рано. Начать надо с Цитата ISO/IEC 14882:2011 12.4/3 A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration (15.4). Цитата ISO/IEC 14882:2011 15.4/14 An implicitly declared special member function (Clause 12) shall have an exception-specification. If f is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification of a function directly invoked by f’s implicit definition; f shall allow all exceptions if any function it directly invokes allows all exceptions, and f shall allow no exceptions if every function it directly invokes allows no exceptions. А вот теперь можете смотреть и думать. Цитата Qraizer @ Так что да, вполне ожидаемо отсутствие исключения в приведённом выше коде для тех, кто не знает C++ fixed Цитата Qraizer @ А что там у вас в C++14 за баги, я не в курсе. У нас всё в порядке. А вот вышеозначенные гранды опять сделали поделки, не выдерживающие элементарной критики. Добавлено Цитата Qraizer @ так что формально деструктор без явной спецификации исключений считается nothrow Деточка, deallocation function - это не деструктор. |
Сообщ.
#10
,
|
|
|
Мальчик, deallocation function – это общее понятие, частным случаем которого являются деструкторы.
|
Сообщ.
#11
,
|
|
|
Цитата Qraizer @ Мальчик, deallocation function – это общее понятие, частным случаем которого являются деструкторы. Нам нужен смайлик рука_кирпич... Цитату, сестра, цитату! |
Сообщ.
#12
,
|
|
|
P.S. std::operator<<<>(std::basic_ostream<>& os, const char* s) не имеет ограничения nothrow.
Добавлено Цитата MyNameIsIgor @ Сфоткай свой экзерсис. Я с удовольствием посмотрю. Буду сильно надеяться, что последний раз. Нам нужен смайлик рука_кирпич... |
Сообщ.
#13
,
|
|
|
Цитата Qraizer @ Сфоткай свой экзерсис. Я с удовольствием посмотрю. Буду сильно надеяться, что последний раз. Цитата Qraizer @ std::operator<<<>(std::basic_ostream<>& os, const char* s) не имеет ограничения nothrow. Совсем не читатель? Цитата MyNameIsIgor @ a function directly invoked by f’s implicit definition; |
Сообщ.
#14
,
|
|
|
korvin, можешь кратенько сформулировать суть холивара?
Добавлено Цитата C++ RAII/exceptions vs Golang defer/panic/recover У RAII перед defer преимущество, по сути, одно. Освобождение ресурса срабатывает всегда при разрушении объекта, причём это происходит и для полей и для базы(в случае наследования). Далее, defer выразим через RAII посредством guard'ов. RAII через defer не сделать. Что касается исключений, то это отдельный холивар. |
Сообщ.
#15
,
|
|
|
Цитата D_KEY @ korvin, можешь кратенько сформулировать суть холивара? Гм... RAII vs defer (как способы освобождения ресурсов) [vs другие способы освобождения ресурсов (using, with, etc), если есть кому что сказать про них] Цитата D_KEY @ У RAII перед defer преимущество, по сути, одно. Освобождение ресурса срабатывает всегда при разрушении объекта, причём это происходит и для полей и для базы(в случае наследования). Да, но такие сложные ресурсы могут запутывать и, опять же, в непредвиденном случае возникновения исключения в деструкторе одного из полей, имеем ту же проблему. Цитата D_KEY @ Далее, defer выразим через RAII посредством guard'ов. Возможно, но будет ли это выражение таким же надёжным или опять его можно будет обойти и ввести систему в некорректное состояние? Цитата D_KEY @ RAII через defer не сделать. Да как-то и желания нет. Цитата D_KEY @ Что касается исключений, то это отдельный холивар. А исключения тут как пример возможности испортить поведение механизма. |