Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 04.11.20 21:09
Оценка:
Типичная ситуация: функция верхнего уровня вызывает функцию более низкого уровня, та — следующую и т.п., и где-то на N-м уровне очередной вызов возвращает ошибку. Если это что-то уникальное, то можно вернуть наверх (хоть через обычные return, хоть через исключения) уникальный код и/или описание. Но если ошибка общего характера (нехватка ресурсов, отказ в доступе, разрыв соединения и т.п.), то неплохо бы вернуть наверх более подробную информацию, которую можно показать пользователю, чтобы он имел более-менее адекватное представление о проблеме.

Например, в винде издавна принято возвращать отовсюду HRESULT. В результате, например, Windows Update при любой проблеме тупо выдает "failed" вместе с HRESULT, и даже по логам не сразу определишь, что и где обломалось. А программы на фреймворках типа .NET, наоборот, могут столь же тупо вывалить пользователю раскрутку стека, из которой он тоже мало что поймет, и которую таки лучше писать в лог. Хочется выдавать нечто промежуточное — не абстрактный "access denied", но и не историю вложенных вызовов в чистом виде.

Возникает соблазн завести какой-нибудь универсальный класс Result, и в процессе возврата изнутри наружу добавлять в объект уточнения, если необходимо. Но если возвращать его обычным образом, через return, то RVO/NRVO в отладочном режиме [практически] не используется, возвращаемые объекты (где будут минимум сотни байт) будут многократно копироваться, а функции нижнего уровня могут вызываться и сотни-тысячи раз в секунду. По той же причине не всегда годятся исключения — функции нижнего уровня не всегда возвращают ошибки, фатальные для верхних уровней.

Другой вариант — использовать TLS, как в винде для GetLastError. А как с этим в Linix/MacOS/Android/iOS?

Вообще, какие способы возврата уточненных результатов из многократно вложенных вызовов ныне считаются кошерными?
результат ошибка код rvo nrvo оптимизация getlasterror вложенный
Re: Возврат ошибок из недр вложенных вызовов
От: varenikAA  
Дата: 05.11.20 01:29
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Вообще, какие способы возврата уточненных результатов из многократно вложенных вызовов ныне считаются кошерными?


Просто оставлю это здесь, к сожалению лиспы не пользуются популярностью в коммерческой разработке,
но это пожалуй самый гибкий подход. Обработка исключений изнутри: Условия и Перезапуск
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re: Возврат ошибок из недр вложенных вызовов
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 05.11.20 04:48
Оценка: 2 (1) +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Возникает соблазн завести какой-нибудь универсальный класс Result, и в процессе возврата изнутри наружу добавлять в объект уточнения, если необходимо. Но если возвращать его обычным образом, через return, то RVO/NRVO в отладочном режиме [практически] не используется, возвращаемые объекты (где будут минимум сотни байт) будут многократно копироваться, а функции нижнего уровня могут вызываться и сотни-тысячи раз в секунду. По той же причине не всегда годятся исключения — функции нижнего уровня не всегда возвращают ошибки, фатальные для верхних уровней.


Не очень понял, чем исключения для такой цели плохи. Мне кажется на оборот, не надо кучи if/else и ты сразу можешь прокинуть то, что хочешь с низу стека к получателю. Если же хочется какой-то дополнительной механики с добавлением деталей, то можно взять исключения из BOOST. Там как раз есть возможность легко пристыковать дополнительные детали.
Re: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 05.11.20 05:52
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Возникает соблазн завести какой-нибудь универсальный класс Result, и в процессе возврата изнутри наружу добавлять в объект уточнения, если необходимо. Но если возвращать его обычным образом, через return, то RVO/NRVO в отладочном режиме [практически] не используется, возвращаемые объекты (где будут минимум сотни байт) будут многократно копироваться, а функции нижнего уровня могут вызываться и сотни-тысячи раз в секунду.


unique_ptr/shared_ptr не поможет? В MSVC с ними плохо?

ЕМ>Другой вариант — использовать TLS, как в винде для GetLastError. А как с этим в Linix/MacOS/Android/iOS?


Отлично в них с TLS.
The God is real, unless declared integer.
Re: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 05.11.20 07:25
Оценка: 2 (1)
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Возникает соблазн завести какой-нибудь универсальный класс Result


Этот соблазн возникает у многих, поэтому в комитет по стандартизации было подано предложение по включению в stdlib шаблонного класса std::expected. Одна из реализаций этого шаблона доступна в виде библиотеки expected_lite. Там же в README можно найти ссылки и на другие реализации.

Кроме того, в Boost с версии 1.70 есть outcome (не привязанный к Boost-у вариант, вроде бы, здесь).

Так же к включению в Boost готовится библиотека LEAF.

EM>Но если возвращать его обычным образом, через return, то RVO/NRVO в отладочном режиме [практически] не используется, возвращаемые объекты (где будут минимум сотни байт) будут многократно копироваться, а функции нижнего уровня могут вызываться и сотни-тысячи раз в секунду.


Кого-то интересует скорость работы в отладочном режиме?
Re[2]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.11.20 09:22
Оценка:
Здравствуйте, kaa.python, Вы писали:

KP>Не очень понял, чем исключения для такой цели плохи.


Я ж специально пояснил, что не все отказы функций нижнего уровня являются фатальными для верхних. В ряде случаев нет другого способа что-то сделать, кроме как тупо перебрать несколько десятков-сотен наборов параметров, последовательно вызывая функции нижнего уровня с каждым из них. Если при каждом вызове функция будет выбрасывать исключение, то накладные расходы станут чрезмерными, а главное — слабопредсказуемыми. Некоторые функции вызываются в достаточно жестком (максимум сотни микросекунд на всю обработку) реалтайме, поэтому исключения там допустимы лишь в фатальных случаях.
Re[2]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.11.20 09:23
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>лиспы не пользуются популярностью в коммерческой разработке


В лиспах вопрос быстродействия и накладных расходов стоит на самых последних позициях.
Re[2]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.11.20 09:24
Оценка:
Здравствуйте, netch80, Вы писали:

N>unique_ptr/shared_ptr не поможет?


Как оно может помочь само по себе?

ЕМ>>Другой вариант — использовать TLS, как в винде для GetLastError. А как с этим в Linix/MacOS/Android/iOS?


N>Отлично в них с TLS.


Во всех?
Re[2]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.11.20 09:29
Оценка:
Здравствуйте, so5team, Вы писали:

S>Этот соблазн возникает у многих, поэтому в комитет по стандартизации было подано предложение по включению в stdlib шаблонного класса std::expected


Поглядел на реализации — выглядит чересчур монструозно. Для программ, не считающих ресурсов, сгодится, но мне нужно что-то более предсказуемое и экономичное.

S>Кого-то интересует скорость работы в отладочном режиме?


Всех, кто делает хоть что-то в реальном времени (звук, видео, управление и т.п.). Если отладочная сборка перестанет успевать за процессом, то отлаживать станет нечего.
Re[3]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 05.11.20 12:05
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

S>>Этот соблазн возникает у многих, поэтому в комитет по стандартизации было подано предложение по включению в stdlib шаблонного класса std::expected


ЕМ>Поглядел на реализации — выглядит чересчур монструозно. Для программ, не считающих ресурсов, сгодится, но мне нужно что-то более предсказуемое и экономичное.


Вы накладные расходы глядя на исходный код "на глазок" определяете? Или сделали таки пару-тройку бенчмарков?

S>>Кого-то интересует скорость работы в отладочном режиме?


ЕМ>Всех, кто делает хоть что-то в реальном времени (звук, видео, управление и т.п.). Если отладочная сборка перестанет успевать за процессом, то отлаживать станет нечего.


Афигеть. И пошаговую отладку в отладчике тоже в реальном времени делаете?
Re: Возврат ошибок из недр вложенных вызовов
От: kov_serg Россия  
Дата: 05.11.20 14:03
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Вообще, какие способы возврата уточненных результатов из многократно вложенных вызовов ныне считаются кошерными?

Логи.
Вообще передавай контекст который определяет как писать и писать ли логи и как реагировать на возникающие ошибки.
Re[4]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.11.20 15:47
Оценка:
Здравствуйте, so5team, Вы писали:

S>Вы накладные расходы глядя на исходный код "на глазок" определяете?


Как минимум, я вижу там возврат объекта по значению из каждой вызываемой функции. Почему это нежелательно как минимум в MS VC++, я оговорил в исходном сообщении.

S>Или сделали таки пару-тройку бенчмарков?


Зачем мне делать бенчмарки, если я знаю, в какой код скомпилируются подобные конструкции, и какие накладные расходы это даст на фоне остального моего кода? А вот в каких-нибудь тормозах вроде современных версий MS VS такое смело можно использовать без бенчмарков, поскольку накладные расходы совершенно ничтожны на фоне остального кода.

S>И пошаговую отладку в отладчике тоже в реальном времени делаете?


Делаю, если достаточно пройтись по обработке уже накопленных данных, и потеря остальных данных в паузе не критична.
Re[2]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.11.20 15:52
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Логи.


Логи хороши для меня, как разработчика, если что-то пошло совсем уж не так. Но во многих случаях достаточно вернуть пользователю мало-мальски конкретную информацию (например, к какому конкретно из файлов/ключей не удалось получить доступ, какая именно из группы операций с устройством не сработала и т.п.), чтобы он сам сообразил, что у него не в порядке.

_>Вообще передавай контекст который определяет как писать и писать ли логи и как реагировать на возникающие ошибки.


Где его передавать? Когда с объектом в определенный период времени работает только один поток — можно передавать его объекту. А когда несколько потоков — только в параметрах каждой функции, или в TLS. Но тогда в TLS можно хранить и описатель нештатной ситуации.
Re[5]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 05.11.20 16:20
Оценка: :)
Здравствуйте, Евгений Музыченко, Вы писали:

S>>Вы накладные расходы глядя на исходный код "на глазок" определяете?


ЕМ>Как минимум, я вижу там возврат объекта по значению из каждой вызываемой функции. Почему это нежелательно как минимум в MS VC++, я оговорил в исходном сообщении.


Объекты объектам рознь. Если вы std::vector<std::string> каждый раз возвращаете и при этом move-семантика никак не задействуется, то... Возможно, вы в принципе что-то делаете не так.

S>>Или сделали таки пару-тройку бенчмарков?


ЕМ>Зачем мне делать бенчмарки, если я знаю, в какой код скомпилируются подобные конструкции, и какие накладные расходы это даст на фоне остального моего кода?


Так вы мало того, что рил-тайм код в отладчике умудряетесь пошагово отлаживать, так еще и одним взглядом определяете во что современные шаблонные кружева транслируются? Вот прям удивительно, что такой мегамонстр за советами на форум обращается

S>>И пошаговую отладку в отладчике тоже в реальном времени делаете?


ЕМ>Делаю, если достаточно пройтись по обработке уже накопленных данных, и потеря остальных данных в паузе не критична.


Ну да, ну да. Реальное время -- оно же такое, не критичное.

Блин, время каких-то офигительных историй. Простите уж, что отвлек ссылками на какие-то незаслуживающего вашего внимания поделки.
Re[3]: Возврат ошибок из недр вложенных вызовов
От: Muxa  
Дата: 05.11.20 16:29
Оценка:
KP>>Не очень понял, чем исключения для такой цели плохи.
ЕМ>Я ж специально пояснил, что не все отказы функций нижнего уровня являются фатальными для верхних. В ряде случаев нет другого способа что-то сделать, кроме как тупо перебрать несколько десятков-сотен наборов параметров, последовательно вызывая функции нижнего уровня с каждым из них.

Звучит так как-будто бы это и не ошибки вовсе, а просто поиск оптимальных значений параметров. Зачем о таком сигнализировать на самый верх?
Re[4]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.11.20 16:36
Оценка:
Здравствуйте, Muxa, Вы писали:

M>Звучит так как-будто бы это и не ошибки вовсе, а просто поиск оптимальных значений параметров.


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

M>Зачем о таком сигнализировать на самый верх?


А если вдруг возвращает "устройство отключено", "отказ в доступе" и т.п., то это уже нештатная ситуация, о которой нужно сообщить именно на самый верх.
Re[5]: Возврат ошибок из недр вложенных вызовов
От: Muxa  
Дата: 05.11.20 16:41
Оценка: +2
M>>Звучит так как-будто бы это и не ошибки вовсе, а просто поиск оптимальных значений параметров.
ЕМ>При помощи множества последовательных вызовов приходится искать, например, поддерживаемые звуковые форматы — в интерфейсах не предусмотрено способа получения исчерпывающего списка хоть конкретных форматов, хоть их диапазонов. Сама система тоже делает множественные вызовы. Если устройство возвращает ошибку "не подходит" то пробуем следующую комбинацию.
Чот не похоже что это будет вызываться сотни тысяч раз в секунду.

M>>Зачем о таком сигнализировать на самый верх?

ЕМ>А если вдруг возвращает "устройство отключено", "отказ в доступе" и т.п., то это уже нештатная ситуация, о которой нужно сообщить именно на самый верх.
Брось исключение. Производительность в этом случае уже не важна.
Re: Возврат ошибок из недр вложенных вызовов
От: Шахтер Интернет  
Дата: 05.11.20 18:44
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Другой вариант — использовать TLS, как в винде для GetLastError.


Насколько я понял, тебе нужен механизм взаимодействия через несколько уровней вызова.
Вообщем, реализовать такой не проблема. Причем именно такой, какой захочешь. Да, нужен TLS.
В функции верхнего уровня регистрируешь обработчик, или даже цепочку в стеке.
Функция нижнего уровня находит обработчик и использует его в соответствии с разработанным вами протоколом.
Можно реализовать эффективную пересылку любого объёма данных. Любой механизм реакции -- с возобновлением или без.
TLS не проблема ни в Windows, ни в Linux. Про другие оси не скажу.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: Возврат ошибок из недр вложенных вызовов
От: reversecode google
Дата: 05.11.20 19:04
Оценка:
в предвери наступающего 2021 года
Евгений все так же не желал осваивать С++ новее стандарта С++98 ...
и не хотел инвестировать свое время в изучение чего то нового ...
Re[6]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.11.20 19:12
Оценка:
Здравствуйте, so5team, Вы писали:

S>Объекты объектам рознь. Если вы std::vector<std::string> каждый раз возвращаете и при этом move-семантика никак не задействуется, то... Возможно, вы в принципе что-то делаете не так.


В результатах кодогенерации MS VC++ я ни разу не видел NRVO, если не включена оптимизация. Как туда можно прикрутить move-семантику, я в принципе не представляю. Если знаете секрет — поделитесь, пожалуйста.

S>Так вы мало того, что рил-тайм код в отладчике умудряетесь пошагово отлаживать


Я уже объяснил, что не весь реалтайм, а только соответствующие части. Что именно Вас в этом удивляет?

S>так еще и одним взглядом определяете во что современные шаблонные кружева транслируются?


"Современные шаблонные кружева" как-то влияют на алгоритмы кодогенерации, и есть примеры, когда для шаблонного класса создается более эффективный код, чем для эквивалентного нешаблонного?

S>Реальное время -- оно же такое, не критичное.


Вы твердо уверены в том, что правильно и полностью понимаете смысл понятия "реальное время"?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.