Re[6]: Legalize throwing destructors! D's scope(failure) and scope(success) in C
От: Evgeny.Panasyuk Россия  
Дата: 01.10.12 20:40
Оценка:
Здравствуйте, Vamp, Вы писали:

EP>>Откуда такая гарантия, учитывая что запись буферизованная?

V>Ну укажи, какие именно ошибки из возвращаемых fflush могут возникнуть внезапно.

внезапно закончилось место в разделе

EP>>То же самое, что и при обычных исключениях

EP>>Их обработка обычно происходит несколькими уровнями выше, чем непосредственно код в котором они произошли, и все объекты тоже уже удаленны. Хотя бы потому, что во многих случаях в том месте где они произошли — недостаточно информации для их обработки/исправления. Это одна из главных фич исключений.
V>При обычных исключениях объект не создан, и никакой работы еще не проделано. То есть если файл нельзя создать — то мы кидаем исключение (хотя я бы и в этом случае обошелся кодом возврата) — и выдаем окошечко, файл не создан, выбери другой.

хм, то есть при работе с объектом типа "File", исключение может произойти только в конструкторе?

V>А когда у тебя файл не закрыт — что ты будешь делать? То есть, ты писал-писал (особенно хорошо, если данные приходили по сети) — и вдруг опаньки? Что РАЗУМНОГО ты можешь сделать в этой ситуации?


Как это относится к кидающим/не кидающим деструкторам? Эта ситуация может случится и без них

EP>>После обычных исключений, ты тоже стреляешь программе в голову?

V>Нет. Но см. выше.

вижу — у тебя исключения только в конструкторах, действительно объекты-то не созданы

EP>>>>Как будешь готовить класс "File"? Где будет flush?

EP>>Ну вот абстрактный пример, два файла пишутся параллельно:
EP>>
EP>>void fsome(/* ... */)
EP>>{
EP>>    OutFile a("a"),b("b");
EP>>    a.write("Hello");
EP>>    b.write("World");
EP>>    // ...
EP>>    b.flush(); // Fail #1
EP>>    a.flush(); // Fail #2
EP>>}
EP>>

EP>>У fsome, следующие постусловие — данные записаны в оба файла. Если fsome не может достичь своего постусловия — то кидается исключение.
EP>>Что ты предлагаешь делать в местах "Fail #1" и "Fail #2"?
V>Оставь ты flush в покое.

Ты предложил вариант с явным вызовом, отдельного flush:

V>В нигде. Будет как отдельный метод. Из деструктора звать fflush не буду, только fclose.

Свой вариант без явного flush, с киданием исключений из деструктора я показал.
Почему бы не поделится своим рецептом приготовления?

V>Мое бескомпромиссное имхо — кидать из деструкторов пытаются те, кто не умеет их готовить.


V>Как думаешь, почему у fstream деструктор не швыряет, а?


наверное боится std::terminate, а is_unwinding у него нет.
Проглатывание ошибок — очень плохое решение.
Re[7]: Legalize throwing destructors! D's scope(failure) and scope(success) in C
От: Andrew S Россия http://alchemy-lab.com
Дата: 01.10.12 21:26
Оценка: +1
EP>>>Откуда такая гарантия, учитывая что запись буферизованная?
V>>Ну укажи, какие именно ошибки из возвращаемых fflush могут возникнуть внезапно.

EP>внезапно закончилось место в разделе


EP>>>То же самое, что и при обычных исключениях

EP>>>Их обработка обычно происходит несколькими уровнями выше, чем непосредственно код в котором они произошли, и все объекты тоже уже удаленны. Хотя бы потому, что во многих случаях в том месте где они произошли — недостаточно информации для их обработки/исправления. Это одна из главных фич исключений.
V>>При обычных исключениях объект не создан, и никакой работы еще не проделано. То есть если файл нельзя создать — то мы кидаем исключение (хотя я бы и в этом случае обошелся кодом возврата) — и выдаем окошечко, файл не создан, выбери другой.

EP>хм, то есть при работе с объектом типа "File", исключение может произойти только в конструкторе?


Как ни странно, но мой опыт говорит, что при работе с объектом уровня File исключение не должно произойти нигде. Это примитив слишком низкого уровня абстракции, чтобы швыряться исключениям. Например, открытие файла очень часто используется для проверки его существования на предмет создания временного. Кидаться в этом случае исключением ну никак нельзя — это логика, а не обработка ошибок.

Касательно fflush. Действительно, делать fflush совместно с fclose безусловно нельзя — далеко не всем (а точнее, вообще не всем) клиентам сервиса File это требуется. Если рассматривать жизненные кейзы, то становится очевидно, что логика принятия решения о вызове или не вызове fflush — это логика уровня абстракции сильно выше, чем File. Например, с т.з. производительности эти операции просто нельзя совмещать на данном уровне.
Касательно fclose. К сожалению, что fclose, что CloseHandle, не позволяют клиенту сделать какие-либо вменяемые действия по восстановлению на уровне File. Все что реально может клиент — констатировать проблему (VERIFY или trace), и забыть про этот описатель, либо попытаться откатить операцию и сделать все наново (уровень сильно выше File). Для действий второго рода у объектов уровня File обычно есть метод Close, которые позволяет при необходимости получить код ошибки и обработать по своему вкусу.
Как все это можно автоматизировать и не вызывать методы File ручками? Обычное решение в этом случае — делается отдельный объект более высокого, чем File, уровня абстракции, который прямо или косвенно использует File и реализует логику прикладного уровня, в т.ч. реакцию на ошибку fflush, например, запись в трейс.
В целом, выкидывание исключения из деструктора представляется достаточно опасной, а главное, бесполезной концепцией (классическую проблему — что делать, если при выкидывании исключения в деструкторе еще исключение — какое должно пролететь и как это обработать — обычно нельзя решить на уровне объекта, уничтожаемого в результате свертки стека). Нужно ли давать пользователю возможность отстрелить себе ногу, если можно (и лучше) этого не делать?
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[7]: Legalize throwing destructors! D's scope(failure) and scope(success) in C
От: Vamp Россия  
Дата: 01.10.12 21:28
Оценка:
V>>Ну укажи, какие именно ошибки из возвращаемых fflush могут возникнуть внезапно.
EP>внезапно закончилось место в разделе
Ага. И что ты можешь сделать в этом случае? Что твой гипотетический catch сделает?

EP>хм, то есть при работе с объектом типа "File", исключение может произойти только в конструкторе?

Не только. При записи тоже может. Только при записи ты можешь перехватить исключение и спросить пользователя, мол, запись-то вдруг обломалась, давай, чини — и повторить попытку, а что ты сделаешь, если кинул деструктор???

EP>Как это относится к кидающим/не кидающим деструкторам? Эта ситуация может случится и без них

Может. И деструктор тут не поможет. Отсюда еще раз — деструктор в принципе не должен выполнять действия, могущие вернуть код ошибки. Потому что есть is_unwinding, что нет — восстановиться в этом случае нельзя.
Да здравствует мыло душистое и веревка пушистая.
Re[8]: Legalize throwing destructors! D's scope(failure) and scope(success) in C
От: Vamp Россия  
Дата: 01.10.12 21:30
Оценка:
AS>В целом, выкидывание исключения из деструктора представляется достаточно опасной, а главное, бесполезной концепцией (классическую проблему — что делать, если при выкидывании исключения в деструкторе еще исключение — какое должно пролететь и как это обработать — обычно нельзя решить на уровне объекта, уничтожаемого в результате свертки стека). Нужно ли давать пользователю возможность отстрелить себе ногу, если можно (и лучше) этого не делать?
Во-во, и именно эту простую мысль я пытаюсь донести до автора.
Да здравствует мыло душистое и веревка пушистая.
Re[8]: Legalize throwing destructors! D's scope(failure) and scope(success) in C
От: Evgeny.Panasyuk Россия  
Дата: 01.10.12 21:46
Оценка:
Здравствуйте, Andrew S, Вы писали:

EP>>хм, то есть при работе с объектом типа "File", исключение может произойти только в конструкторе?

AS>Как ни странно, но мой опыт говорит, что при работе с объектом уровня File исключение не должно произойти нигде. Это примитив слишком низкого уровня абстракции, чтобы швыряться исключениям.

пусть будет не файл, пусть будет что-то, с отложенным действием. Семантика:
{
    Something a,b;
    // ...
    b.deferred(); // may throw
    a.deferred(); // may throw
}

Почему бы не использовать предложенный метод, и вместо этого писать:
{
    Something a,b;
    // ...
}

?

AS>В целом, выкидывание исключения из деструктора представляется достаточно опасной, а главное, бесполезной концепцией (классическую проблему — что делать, если при выкидывании исключения в деструкторе еще исключение — какое должно пролететь и как это обработать — обычно нельзя решить на уровне объекта, уничтожаемого в результате свертки стека).


Первое сообщение топика читал? А документацию?
А про двух-фазную деструкцию
Автор: Evgeny.Panasyuk
Дата: 01.10.12
?

AS>Нужно ли давать пользователю возможность отстрелить себе ногу, если можно (и лучше) этого не делать?


http://www.rsdn.ru/forum/cpp/4909480.1
Автор: Evgeny.Panasyuk
Дата: 28.09.12

При текущем положении дел, кидание исключений из деструкторов опасное занятие, даже если не брать во внимание технические проблемы — большинство кода просто не рассчитано на исключения из деструкторов. Я не агитирую за необдуманное кидание исключений из деструкторов налево и направо (несмотря на название топика)

Re[8]: Legalize throwing destructors! D's scope(failure) and scope(success) in C
От: Evgeny.Panasyuk Россия  
Дата: 01.10.12 21:58
Оценка:
Здравствуйте, Vamp, Вы писали:

V>>>Ну укажи, какие именно ошибки из возвращаемых fflush могут возникнуть внезапно.

EP>>внезапно закончилось место в разделе
V>Ага. И что ты можешь сделать в этом случае? Что твой гипотетический catch сделает?

например, сказать пользователю, он примет меры, а потом повторить заново.

EP>>хм, то есть при работе с объектом типа "File", исключение может произойти только в конструкторе?

V>Не только. При записи тоже может. Только при записи ты можешь перехватить исключение и спросить пользователя, мол, запись-то вдруг обломалась, давай, чини — и повторить попытку, а что ты сделаешь, если кинул деструктор???

Я пытаюсь понять, ты говоришь о try/catch исключений вокруг каждого вызова? Ещё раз:

Их обработка обычно происходит несколькими уровнями выше, чем непосредственно код в котором они произошли, и все объекты тоже уже удаленны. Хотя бы потому, что во многих случаях в том месте где они произошли — недостаточно информации для их обработки/исправления. Это одна из главных фич исключений.
Использовать исключения, для кода, в котором каждый вызов функции обвёрнут в try/catch — глупо, уж лучше коды возврата (или что ты хотел показать свои примером?).


Если ты готов сразу отреагировать на ошибку flush'а, в коде его вызвавшем, не кидая исключения на более высокие уровни — то естественно, скорей всего тут и исключения не нужны, достаточно кода возврата.
Если же после фейла flush'а, кидается исключение на более высокие уровни — то какая разница, пришло оно из деструктора или нет?

V>>А когда у тебя файл не закрыт — что ты будешь делать? То есть, ты писал-писал (особенно хорошо, если данные приходили по сети) — и вдруг опаньки? Что РАЗУМНОГО ты можешь сделать в этой ситуации?

EP>>Как это относится к кидающим/не кидающим деструкторам? Эта ситуация может случится и без них
V>Может. И деструктор тут не поможет. Отсюда еще раз — деструктор в принципе не должен выполнять действия, могущие вернуть код ошибки. Потому что есть is_unwinding, что нет — восстановиться в этом случае нельзя.

А как получилось это "отсюда". Таким же маневром можно сказать, что любой код "в принципе не должен выполнять действия, могущие вернуть код ошибки", так как в нём тоже может произойти эта ситуация.
Re[9]: Legalize throwing destructors! D's scope(failure) and scope(success) in C
От: Evgeny.Panasyuk Россия  
Дата: 01.10.12 22:05
Оценка:
Здравствуйте, Vamp, Вы писали:

AS>>В целом, выкидывание исключения из деструктора представляется достаточно опасной, а главное, бесполезной концепцией (классическую проблему — что делать, если при выкидывании исключения в деструкторе еще исключение — какое должно пролететь и как это обработать — обычно нельзя решить на уровне объекта, уничтожаемого в результате свертки стека). Нужно ли давать пользователю возможность отстрелить себе ногу, если можно (и лучше) этого не делать?

V>Во-во, и именно эту простую мысль я пытаюсь донести до автора.

Какую именно?
1. два исключения через один стэк-фрейм? — ну так is_unwinding в первом сообщении описан.
2. отложенные действия на объектах, которые могут сфейлится не нужны, либо пользователь не должен знать об этих фэйлах?
3. is_unwinding не нужен?
4. вызов std::terminate, то есть беспощадное убийство программы, это нормально? И не нужно пытаться исправить ситуацию?
Re[9]: Legalize throwing destructors! D's scope(failure) and scope(success) in C
От: Andrew S Россия http://alchemy-lab.com
Дата: 02.10.12 21:15
Оценка:
EP>>>хм, то есть при работе с объектом типа "File", исключение может произойти только в конструкторе?
AS>>Как ни странно, но мой опыт говорит, что при работе с объектом уровня File исключение не должно произойти нигде. Это примитив слишком низкого уровня абстракции, чтобы швыряться исключениям.

EP>пусть будет не файл, пусть будет что-то, с отложенным действием. Семантика:

EP>
EP>{
EP>    Something a,b;
EP>    // ...
EP>    b.deferred(); // may throw
EP>    a.deferred(); // may throw
EP>}
EP>

EP>Почему бы не использовать предложенный метод, и вместо этого писать:
EP>
EP>{
EP>    Something a,b;
EP>    // ...
EP>}
EP>

EP>?

Хотелось бы понять, зачем. Если у Something нет других методов, кроме deferred, тогда объект не нужен — это функция. Если есть — тогда принимать решение по контракту того, что должно происходить в деструкторе объекта при ошибке освобождения ресурса должен либо внешний код на этом же уровне (т.е. исключение тут не нужно), либо действие тривиально и сводится только к констатации факта ошибки (VERIFY, TRACE), либо при использовании контрактов — самоубийству либо ничего не деланью, просто потому, что сделать ничего нельзя.

В общем, можете привести пример кроме File (его мы уже взвесили и вроде как признали его непригодным для демонстрации бананьев), когда САМ объект гварда (а то, что мы тут обсуждаем, именно это — других примеров я пока не вижу) не может сделать все нужные действия по обработке ошибки освобождения охраняемого ресурса? Я такой пример знаю, правда, я знаю, как его надо решать — без использования исключений вообще.


AS>>В целом, выкидывание исключения из деструктора представляется достаточно опасной, а главное, бесполезной концепцией (классическую проблему — что делать, если при выкидывании исключения в деструкторе еще исключение — какое должно пролететь и как это обработать — обычно нельзя решить на уровне объекта, уничтожаемого в результате свертки стека).


EP>Первое сообщение топика читал? А документацию?

EP>А про двух-фазную деструкцию
Автор: Evgeny.Panasyuk
Дата: 01.10.12
?


Смотрел, и читал. Примеров сценариев использования — не увидел.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[10]: Legalize throwing destructors! D's scope(failure) and scope(success) in
От: Evgeny.Panasyuk Россия  
Дата: 02.10.12 22:01
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>Хотелось бы понять, зачем. Если у Something нет других методов, кроме deferred, тогда объект не нужен — это функция.


вообще я подразумевал что есть другие методы.
Но, если бы даже не было, и была бы одна только функция deferred — которая должна вызываться в конце scope, если нет исключения, то это типичный scope(success) из языка D (https://github.com/panaseleus/stack_unwinding#d-style-scope-guardsactions — тут и ссылки и примеры), а никак не обычная функция.
Без наличия таких deferred действий приходится использовать костыли в виде ScopeGuard'ких commit/release:
* http://www.boost.org/doc/libs/1_51_0/libs/scope_exit/doc/html/index.html
* http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Scope_Guard
* http://www.drdobbs.com/cpp/generic-change-the-way-you-write-excepti/184403758

AS>Если есть — тогда принимать решение по контракту того, что должно происходить в деструкторе объекта при ошибке освобождения ресурса должен либо внешний код на этом же уровне (т.е. исключение тут не нужно), либо действие тривиально и сводится только к констатации факта ошибки (VERIFY, TRACE), либо при использовании контрактов — самоубийству либо ничего не деланью, просто потому, что сделать ничего нельзя.


При чём тут деструктор и ресурсы?
{
    Something a,b;
    // ...
    b.deferred(); // may throw
    a.deferred(); // may throw
}

Сейчас ведь оно как раз не в деструкторе делается

AS>В общем, можете привести пример кроме File (его мы уже взвесили и вроде как признали его непригодным для демонстрации бананьев),


Я не признавал его непригодным — пример как раз таки нормальный. Я хотел отойти от конкретного примера к обобщённому паттерну отложенных действий.
Дискуссия начала скатываться к обсуждению нужны ли вообще File'у исключения:

AS>Как ни странно, но мой опыт говорит, что при работе с объектом уровня File исключение не должно произойти нигде

Продолжать разговор в этом ключе мне не интересно.

AS>когда САМ объект гварда (а то, что мы тут обсуждаем, именно это — других примеров я пока не вижу) не может сделать все нужные действия по обработке ошибки освобождения охраняемого ресурса? Я такой пример знаю, правда, я знаю, как его надо решать — без использования исключений вообще.


А это не освобождение ресурсов фейлится, фейлится отложенное действие. Само освобождение ресурсов крайне редко может фейлится.
Я вроде об этом уже говорил
Автор: Evgeny.Panasyuk
Дата: 01.10.12
:

1. Освобождение ресурсов не должно фейлится (“letting go of a resource” must never fail Herb Sutter http://cpp-next.com/archive/2012/08/evil-or-just-misunderstood/)
2. Освобождение ресурсов должно произойти в любом случае — утечек быть не должно
3. Поддержка отложенных действий (flush) — желательна. Такие действия могут фэйлится
4. Если отложенное действие фэйлится — пользователь должен узнать об этом. Проглатывание исключений (потеря информации) — не является хорошим решением.

Даже если фейлится отложенное действие, ресурсы всё равно освобожадются.

AS>>>В целом, выкидывание исключения из деструктора представляется достаточно опасной, а главное, бесполезной концепцией (классическую проблему — что делать, если при выкидывании исключения в деструкторе еще исключение — какое должно пролететь и как это обработать — обычно нельзя решить на уровне объекта, уничтожаемого в результате свертки стека).

EP>>Первое сообщение топика читал? А документацию?
EP>>А про двух-фазную деструкцию
Автор: Evgeny.Panasyuk
Дата: 01.10.12
?

AS>Смотрел, и читал. Примеров сценариев использования — не увидел.

Что по этому поводу скажешь?

AS>классическую проблему — что делать, если при выкидывании исключения в деструкторе еще исключение

Например в свете этих двух примеров:
1. https://github.com/panaseleus/stack_unwinding/blob/master/examples/scope_actions.cpp
2. https://github.com/panaseleus/stack_unwinding/blob/master/examples/boost_scopes.cpp
int main(int,char *[])
{
    try
    {
        cout << "Case #1: stack unwinding" << endl;
        BOOST_SCOPE_EXIT(void) { cout << "exit" << endl; } BOOST_SCOPE_EXIT_END
        BOOST_SCOPE_FAILURE(void) { cout << "failure" << endl; } BOOST_SCOPE_FAILURE_END
        BOOST_SCOPE_SUCCESS(void) { cout << "success" << endl; } BOOST_SCOPE_SUCCESS_END
        throw 1;
    } catch(int){}
    {
        cout << "Case #2: normal exit" << endl;
        BOOST_SCOPE_EXIT(void) { cout << "exit" << endl; } BOOST_SCOPE_EXIT_END
        BOOST_SCOPE_FAILURE(void) { cout << "failure" << endl; } BOOST_SCOPE_FAILURE_END
        BOOST_SCOPE_SUCCESS(void) { cout << "success" << endl; } BOOST_SCOPE_SUCCESS_END
    }
    return 0;
}

ExpectedStdoutTest test_cout
(
        "Case #1: stack unwinding\n"
        "failure\n"
        "exit\n"
        "Case #2: normal exit\n"
        "success\n"
        "exit\n"
);
Re[8]: Legalize throwing destructors! D's scope(failure) and scope(success) in C
От: Erop Россия  
Дата: 03.10.12 02:18
Оценка: 12 (1) +1
Здравствуйте, Vamp, Вы писали:

V>>>Ну укажи, какие именно ошибки из возвращаемых fflush могут возникнуть внезапно.

EP>>внезапно закончилось место в разделе
V>Ага. И что ты можешь сделать в этом случае? Что твой гипотетический catch сделает?

Что-нибудь потрёшь?..

V>Не только. При записи тоже может. Только при записи ты можешь перехватить исключение и спросить пользователя, мол, запись-то вдруг обломалась, давай, чини — и повторить попытку, а что ты сделаешь, если кинул деструктор???

Тоже самое. Смотри.
try {
    writeDocument();
catch( exception& e ) {
    // обработчик
}
какая разница, на каком конкретно этапе обломилась запись внутри writeDocument()?

V>Может. И деструктор тут не поможет. Отсюда еще раз — деструктор в принципе не должен выполнять действия, могущие вернуть код ошибки. Потому что есть is_unwinding, что нет — восстановиться в этом случае нельзя.


Почему нельзя? Часто есть боле высокий уровень абстракции, на котором можно...
Ну, например, запись в файл не удалась с какой-угодно ошибкой, можно показать пользователю диагностику, и предоставить возможность попробовать записать в файл ещё раз

з. ы.
Я сам по себе сторонник медленного газа, в смысле противники исключений в деструкторах. IMHO, с ними сложнее код поддерживать, но ни о какой принципиальной их невозможности или бессмысленности речи не идёт вроде...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: Legalize throwing destructors! D's scope(failure) and scope(success) in C
От: Erop Россия  
Дата: 03.10.12 02:20
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>пусть будет не файл, пусть будет что-то, с отложенным действием. Семантика:

EP>
EP>{
EP>    Something a,b;
EP>    // ...
EP>    b.deferred(); // may throw
EP>    a.deferred(); // may throw
EP>}
EP>

EP>Почему бы не использовать предложенный метод, и вместо этого писать:
EP>
EP>{
EP>    Something a,b;
EP>    // ...
EP>}
EP>

EP>?

Потому, что это намного менее очевидно для программиста поддерживающего код...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: Legalize throwing destructors! D's scope(failure) and scope(success) in
От: Evgeny.Panasyuk Россия  
Дата: 03.10.12 11:08
Оценка:
Здравствуйте, Erop, Вы писали:

EP>>пусть будет не файл, пусть будет что-то, с отложенным действием. Семантика:

EP>>
EP>>{
EP>>    Something a,b;
EP>>    // ...
EP>>    b.deferred(); // may throw
EP>>    a.deferred(); // may throw
EP>>}
EP>>

EP>>Почему бы не использовать предложенный метод, и вместо этого писать:
EP>>
EP>>{
EP>>    Something a,b;
EP>>    // ...
EP>>}
EP>>

EP>>?
E>Потому, что это намного менее очевидно для программиста поддерживающего код...

Согласен, такой момент есть, и он немаловажен.
Все кто будет касаться такого кода должны быть осведомлены об отложенных действиях и кидающихся деструкторах. Иначе у них может даже не возникнуть мысли посмотреть в документацию.
Желательно рядом с каждым созданием этого "Something", ставить ссылку в комментарий.
Либо, использовать более явную схему:
{
    Something a,b;
    BOOST_SCOPE_SUCCESS(void) { b.deferred(); // may throw } BOOST_SCOPE_SUCCESS_END
    BOOST_SCOPE_SUCCESS(void) { a.deferred(); // may throw } BOOST_SCOPE_SUCCESS_END
    // ...
}

Важным отличием от ручного расстановки вызовов .deferred() является то, что этот код вызывается на любом выходе из scope (если не было исключения..). то есть в "// ...", могут быть multiple return's, break's, etc..
Re[11]: Legalize throwing destructors! D's scope(failure) and scope(success) in
От: Evgeny.Panasyuk Россия  
Дата: 03.10.12 11:09
Оценка:
EP>
EP>{
EP>    Something a,b;
EP>    BOOST_SCOPE_SUCCESS(void) { b.deferred(); /* may throw */ } BOOST_SCOPE_SUCCESS_END
EP>    BOOST_SCOPE_SUCCESS(void) { a.deferred(); /* may throw */ } BOOST_SCOPE_SUCCESS_END
EP>    // ...
EP>}
EP>
Re[11]: Legalize throwing destructors! D's scope(failure) and scope(success) in
От: Erop Россия  
Дата: 03.10.12 11:43
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Важным отличием от ручного расстановки вызовов .deferred() является то, что этот код вызывается на любом выходе из scope (если не было исключения..). то есть в "// ...", могут быть multiple return's, break's, etc..


Ну я в такой ситаации стронник упрощения кода, или, на крайняк, использования С'шных goto-based подходов, а не дальнейшего запутывания кода.
Но на вкус и цвет, как известно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[12]: Legalize throwing destructors! D's scope(failure) and scope(success) in
От: Evgeny.Panasyuk Россия  
Дата: 03.10.12 12:14
Оценка:
Здравствуйте, Erop, Вы писали:

EP>>Важным отличием от ручного расстановки вызовов .deferred() является то, что этот код вызывается на любом выходе из scope (если не было исключения..). то есть в "// ...", могут быть multiple return's, break's, etc..

E>Ну я в такой ситаации стронник упрощения кода, или, на крайняк, использования С'шных goto-based подходов, а не дальнейшего запутывания кода.
E>Но на вкус и цвет, как известно...

Безусловно, код большого размера, с множественными возвратами, break и т.п., — редко когда оправдан.
Но если не рассматривать моральную сторону вопроса — IMO лучше с scope(exit), scope(failure) и с scope(success) — потому что семантика действия зашита в код. При ручном .deferred() "другой" программист может его не заметить и поставить где-нибудь return.
Кстати, вот слайды Александреску: http://ecn.channel9.msdn.com/events/LangNEXT2012/AndreiLangNext.pdf
Re[9]: Legalize throwing destructors! D's scope(failure) and scope(success) in C
От: Vamp Россия  
Дата: 03.10.12 12:54
Оценка:
E>Что-нибудь потрёшь?..
Потереть ты, конечно, можешь — можно хоть файлвую систему пересоздать — только объект-то тю-тю! Нету его больше, так что повторить операцию никак не получится. В этом и есть (я все пытаюсь донести эту мысль) принципиальное отличие исключений в деструкторах от исключений в других местах. Потому что,
а. Исключение в конструкторе — объект не создан, действие не начато, можно попробовать начать еще раз или вообще забить. Программа в консистном состоянии.
б. Исключение по ходу работы — объект существует, контекст существует, операция сорвалась — можно повтороить операцию еще раз.
в. Исключение в деструкторе — контекст утрачен безвозвратно! Никакое восстановление невозможно принципиально.

E>какая разница, на каком конкретно этапе обломилась запись внутри writeDocument()?

См. выше.

E>Почему нельзя? Часто есть боле высокий уровень абстракции, на котором можно...

E>Ну, например, запись в файл не удалась с какой-угодно ошибкой, можно показать пользователю диагностику, и предоставить возможность попробовать записать в файл ещё раз
Да — если обломился обычный write. (Тут, к слову, я абсолютно согласен с Андреем — в объектах, инкапсулирующих логику работы с файлами, исключениям на самом деле вообще не место, за, пожалуй, единственным исключение — попыткой записи/чтения в неоткрытый файл — но для дискуссии оставим). Write обломился, но можно повторить. А деструктор возможности повторить НЕ ДАЕТ!
Да здравствует мыло душистое и веревка пушистая.
Re[10]: Legalize throwing destructors! D's scope(failure) and scope(success) in
От: Evgeny.Panasyuk Россия  
Дата: 03.10.12 13:33
Оценка:
Здравствуйте, Vamp, Вы писали:

E>>Что-нибудь потрёшь?..

V>Потереть ты, конечно, можешь — можно хоть файлвую систему пересоздать — только объект-то тю-тю! Нету его больше, так что повторить операцию никак не получится. В этом и есть (я все пытаюсь донести эту мысль) принципиальное отличие исключений в деструкторах от исключений в других местах. Потому что,

Если у тебя действительно код:
void f()
{
    File a("some");
    try
    {
        a.write("...");
    }
    catch(/*something*/)
    {
        /*do something*/
    }
    // ...
    try
    {
        a.flush()
    }
    catch(/*something*/)
    {
        // do something
    }
}

То действительно, исключения в деструкторах тебе не нужны. Но, по всей видимости, при таком коде они вообще не нужны, ну кроме конструкторов
А вот если же код вида:
void f()
{
    File a("some");
    a.write("...");
    // ...
    a.flush()
}

То какая разница вызывающему коду, откуда именно прилетело исключение — из явного flush, или из деструктора?

V>в. Исключение в деструкторе — контекст утрачен безвозвратно! Никакое восстановление невозможно принципиально.


Точно также как и утрачен, в случае когда ОБЫЧНОЕ plain-vanilla исключение ловится уровнями выше
А это, ещё раз замечу, default use-case для исключений.

По поводу утраченного контекста, и невозможности "повторить" вызов деструктора, процитируюДейва Абрахамса:

I have serious problems with your suggestion that re-try-ability is fundamental to what can or should report an error, but leaving that argument aside for the time being, consider this: the exception can always carry any information needed to re-try these side-effects.
...
I’ll say the same thing to you that I said to Herb: the ability to usefully re-try an operation has no obvious bearing on whether it’s a good idea to report that the operation failed. In fact, I’ll go further: if the best response to a particular problem is likely to be “try that again,” an exception is probably not the most appropriate way to report the situation, because it’ll usually need to be re-tried very close to the place where it occurred.
...
Here’s another way of looking at it: destructors are the only way we have in C++ of attaching side-effects to block exit (c.f. finally in other languages), and, yes, to the destruction of other objects, neither one of which is inherently a bad thing to do. Side-effects can fail to complete, and when they do, there are reasons to want to know about it.

Re[10]: Legalize throwing destructors! D's scope(failure) and scope(success) in
От: Erop Россия  
Дата: 04.10.12 12:49
Оценка: +1
Здравствуйте, Vamp, Вы писали:

V>в. Исключение в деструкторе — контекст утрачен безвозвратно! Никакое восстановление невозможно принципиально.

Может быть контекст более высокого уровня...

Вообще, какой-то странный аргумент. Вот возьмём, например, файл. Положим файл вернул из Write, что диск поглупел и больше ничего запомнить не может. Что мы можем исправить такое, для чего нам нужен объякт файла?

V>См. выше.

Вот постарайся таки объяснить какая разница, Write провалится или Close...

E>>V>Да — если обломился обычный write. (Тут, к слову, я абсолютно согласен с Андреем — в объектах, инкапсулирующих логику работы с файлами, исключениям на самом деле вообще не место, за, пожалуй, единственным исключение — попыткой записи/чтения в неоткрытый файл — но для дискуссии оставим). Write обломился, но можно повторить. А деструктор возможности повторить НЕ ДАЕТ!


Чего повторить? И зачем? А вдруг он что-то частично записал. а что-то нет?
Ну и вообще, для многих задач запись документа в файл выглядит, как атомарная операция, и если она провалилась, то логичнее попробовать в другой файл сохранить, например, а не пытаться повторить попытку записи того же куска файла,..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Legalize throwing destructors! D's scope(failure) and scope(success) in C++
От: Evgeny.Panasyuk Россия  
Дата: 11.01.14 11:19
Оценка: 20 (2)
EP>stack_unwinding это маленькая header-only библиотека, которая реализует примитив(class unwinding_indicator) позволяющий определить, был ли вызван деструктор объекта из-за раскрутки стэка или "нормальным" образом

Интегрирована в Facebook.Folly:

Added SCOPE_FAIL and SCOPE_SUCCESS macros in non-portable C++.

Summary:
Added SCOPE_FAIL and SCOPE_SUCCESS macros in non-portable C++. The macros are similar to D's scope(failure) and scope(success).
Currently the supported platforms are GCC and MSVC. For all others, std::uncaught_exception() is used, which will fail if the macros are used in a destructor called during stack unwinding.
@override-unit-failures

Test Plan:
1. Added new unit test to ScopeGuardTest.cpp.
2. Ran fbconfig -r folly && fbmake dbg
3. Ran _build/dbg/folly/test/scope_guard_test to make sure my unit test was running and passing.

Reviewed By: andrei.alexandrescu@fb.com

FB internal diff: D1033621

Re[2]: Legalize throwing destructors! D's scope(failure) and scope(success) in C
От: niXman Ниоткуда https://github.com/niXman
Дата: 11.01.14 15:59
Оценка:

Daniel Marinescu

а это кто? или это не твой коммит?

зы
в ФБ только румыны работают? Оо
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.