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

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


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

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

ЕМ>А если вдруг возвращает "устройство отключено", "отказ в доступе" и т.п., то это уже нештатная ситуация, о которой нужно сообщить именно на самый верх.
Брось исключение. Производительность в этом случае уже не важна.
Re: Возврат ошибок из недр вложенных вызовов
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 06.11.20 07:45
Оценка: +2
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Типичная ситуация: функция верхнего уровня вызывает функцию более низкого уровня, та — следующую и т.п., и где-то на N-м уровне очередной вызов возвращает ошибку. Если это что-то уникальное, то можно вернуть наверх (хоть через обычные return, хоть через исключения) уникальный код и/или описание. Но если ошибка общего характера (нехватка ресурсов, отказ в доступе, разрыв соединения и т.п.), то неплохо бы вернуть наверх более подробную информацию, которую можно показать пользователю, чтобы он имел более-менее адекватное представление о проблеме.


1. [Firebird]: I/O error during "WriteFile" operation for file "D:\DATABASE\RAM\IBP_TEST_FB30_D3_2.GDB"
Error while trying to write to file
Неверный дескриптор.
2. [LCPI.IBProvider.5]: Ошибка подтверждения транзакции. Транзакция будет отменена.
3. [Firebird]: internal Firebird consistency check (can't continue after bugcheck)
4. [LCPI.IBProvider.5]: Ошибка отката транзакции.

По неизвестной причине зафиксировать транзакцию не удалось. Данная транзакция была отменена.
COM Error Code: XACT_E_COMMITFAILED


Исключение (на базе std::exception) возит коллекцию описаний проблемы.

Каждый уровень (в catch-секциях) может добавить свое описание к произошедшей проблеме.

... уже более 18-ти лет как
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[5]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 06.11.20 15:44
Оценка: +1 -1
Здравствуйте, netch80, Вы писали:

N>>>Во-первых, как уже сказано, и в отладочном режиме скорость может быть важна, и критически важна. И тогда может и отладчик включаться (но лучше — в неинтерактивном режиме, а, например, со скриптами на точки останова).

S>>Остается позавидовать тем, у кого в Debug режиме производительность достаточная для решения их задач. И кто готов ходить по граблям "в Debug все работает, а в Release какие-то странные вещи происходят" просто потому, что без отладчика ни на что не годен.

N>Какие у вас основания для подобных домыслов, кроме собственной буйной фантазии?


Ну давайте посмотрим. Режим Debug -- это ведь не только отсутствие оптимизаций со стороны компилятора. Это ведь и выполнение assert-ов, которые могут быть в изобилии разборосаны в коде (причем не столько в вашем собственном, сколько в коде использованных вами сторонних библиотек) + (возможно) дополнительные куски проверок и других форм defensive programming, которые включаются только в Debug режиме (опять же, больше в сторонних библиотеках) + (возможно) специальные отладочные фокусы в STL (вроде STL от MS с дополнительными проверками в итераторах) + (возможно) специальные версии new/delete, которые выполняют дополнительные проверки и/или несколько иначе располагают данные в памяти (добавляют специальные проверочные фрагменты до/после выделенного блока). Все это не может не внести значимый оверхед по сравнению с Release режимом.

Просто для иллюстрации: специально после того как утром прочел ваш ответ прогнал один из простеньких бенчмарков нашего RESTinio. В Debug сборке 50K req/s, в Release 150K req/s. Ну вот нельзя всерьез говорить о важности скорости в Debug-е, если просадка в 3 раза на ровном месте.

Изрядная часть реально сложных багов возникает на максимальных нагрузках при максимальной производительности. Когда минимальные задержки и срабатывают сценарии, о которых разработчик даже никогда не задумывался, а в Debug режиме даже близко к ним подойти не может, потому что скорости тупо не хватает для повторения. Могу только пожелать удачи в борьбе с такими проблемами посредством пошаговой отладки в отладчике.

N>>>Во-вторых, в остальном умные вещи пишете, а тут — такую древнюю наркоманию.

S>>Я тут уже после первого упоминания об отладке реалтайм кода в отладчике перестал всерьез что-либо писать.

N>Ну вот очень жаль, что вы в ответ на вполне разумные вещи включили дурочку.


У меня был опыт с реальным временем в прошлом, а сейчас время от времени приходится иметь дело с потоками событий в десятки тысяч в секунду. И когда кто-то мне начинает вещать про полезность отладчика в таких условиях, то я снимаю лапшу с ушей и, если есть настроение, начинаю прикалываться над расказчиками этих удивительных историй. Вот как в данном случае.
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[7]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.11.20 16:36
Оценка: 1 (1)
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Бывает так, что в релизе все (в смысле многопоточности) успевают проскочить через проблемное место, а в debug-сборке (именно из за тормозов) не успевают.


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

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

Логи.
Вообще передавай контекст который определяет как писать и писать ли логи и как реагировать на возникающие ошибки.
Re[5]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 05.11.20 16:20
Оценка: :)
Здравствуйте, Евгений Музыченко, Вы писали:

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


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


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

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


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


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

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


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


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

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

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


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

R>в предвери наступающего 2021 года

R>Евгений все так же не желал осваивать С++ новее стандарта С++98 ...

Обижаете, C++03. Я давно хочу C++11, но последние студии, в компиляторах которых он нормально поддерживается, раздражают своими тормозами.

R>и не хотел инвестировать свое время в изучение чего то нового ...


А что нового изучать, когда я до сих пор делаю в основном ядерный код?
Re[7]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 05.11.20 20:03
Оценка: -1
Здравствуйте, Евгений Музыченко, Вы писали:

EM>Как туда можно прикрутить move-семантику, я в принципе не представляю. Если знаете секрет — поделитесь, пожалуйста.


Может как-то так, если уж вы принципиально не включаете оптимизацию в компиляторе:
std::vector<std::string> child() {...}

std::vector<std::string> parent() {
  ...
  auto r = std::move(child()); // (1)
  ...
  return std::move(r); // (2)
}

Но для современных компиляторов этот явный move в точке (2) -- это как раз принудительная пессимизация. А move в точке (1) не имеет смысла.

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


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


Удивляет, что есть человек, который может пошагово отлаживать реалтаймовый код в отладчике.

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


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


Современные шаблонные кружева влияют на то, что видит человек в коде. Там может быть шаблонный класс, который наследуется от кучи других шаблонных классов, которые для какого-то случая имеют специализации и все это схлопывается во что-то благодаря empty base optimization.

Вы, походу, все это можете увидеть просто глазом. Впрочем, если вам под силу пошагово отлаживать реалтаймовый код, то вам и это по плечу.

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


ЕМ>Вы твердо уверены в том, что правильно и полностью понимаете смысл понятия "реальное время"?


До ваших откровений был уверен. Но теперь сильно сомневаюсь.
Отредактировано 05.11.2020 20:48 so5team . Предыдущая версия .
Re[3]: Возврат ошибок из недр вложенных вызовов
От: reversecode google
Дата: 05.11.20 20:11
Оценка: :)
студия это что, редактор для текстовых файлов ?
пишите как все нормальные программисты — far+wdk/wsdk+опционально clang
Re[2]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.11.20 06:42
Оценка: +1
Здравствуйте, so5team, Вы писали:

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


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

Во-вторых, в остальном умные вещи пишете, а тут — такую древнюю наркоманию. Все эти Debug/Release — концептуальные костыли для самых примитивных требований. В современном серьёзном продукте 95% кода должно компилироваться с максимумом жёсткости против ошибок разработки даже на том, что называлось Release, 1-2% критического пути — вылизано с максимумом хитрых оптимизаций даже при "Debug", и только оставшиеся несколько процентов могут хоть как-то зависеть от режима сборки. И режимы должны выставляться не для кода в целом, а гранулироваться до файла, функции или даже блока кода. Это на юзерленде, но к ядру может ещё больше относиться. Конечно, отрасль страшно консервативна и будет ещё 20 лет тормозить, но если вы где-то не видите возможности регулировать хотя бы оптимизации под конкретную функцию — самое время начинать бить ногами, чтобы авторы компилятора/среды проснулись.
The God is real, unless declared integer.
Re[3]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 06.11.20 06:58
Оценка: -1
Здравствуйте, netch80, Вы писали:

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


N>Во-первых, как уже сказано, и в отладочном режиме скорость может быть важна, и критически важна. И тогда может и отладчик включаться (но лучше — в неинтерактивном режиме, а, например, со скриптами на точки останова).


Остается позавидовать тем, у кого в Debug режиме производительность достаточная для решения их задач. И кто готов ходить по граблям "в Debug все работает, а в Release какие-то странные вещи происходят" просто потому, что без отладчика ни на что не годен.

N>Во-вторых, в остальном умные вещи пишете, а тут — такую древнюю наркоманию.


Я тут уже после первого упоминания об отладке реалтайм кода в отладчике перестал всерьез что-либо писать.
Re[2]: Возврат ошибок из недр вложенных вызовов
От: bnk СССР http://unmanagedvisio.com/
Дата: 06.11.20 11:44
Оценка: +1
Здравствуйте, edton, Вы писали:

E>Здравствуйте, Евгений Музыченко, Вы писали:


ЕМ>> то неплохо бы вернуть наверх более подробную информацию, которую можно показать пользователю, чтобы он имел более-менее адекватное представление о проблеме.


E>"Подробная информация, которую можно показать пользователю" в целом ограничена количеством заранее заготовленных строк, которые мы показываем в messagebox или еще где, даже если это строки вида "Не удалось открыть файл %s в папке %s потому, что %s" Показывать пользователю что то более сложное чаще всего (от софта и аудитории конечно зависит) не имеет смысла. Пользователю ведь зачем это сообщение — или чтобы разобраться самому или отправить потенциальный баг репорт разработчику. Если речь о том, чтобы разобраться самому пользователю, то даже большинство ошибок системных вызовов можно свести к нескольким десяткам заготовленных строк с высокой вероятностью, что они более или менее опишут проблему, и самое главное помогут ее решить пользователю.


Именно что... Кроме банального "Что-то пошло не так" + guid, что еще разумного в наше время можно сделать?
Ну понятно, по guid где-то должен быть доступен полный лог, с ошибками и т.п.
Re[4]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.11.20 15:08
Оценка: +1
Здравствуйте, so5team, Вы писали:

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


N>>Во-первых, как уже сказано, и в отладочном режиме скорость может быть важна, и критически важна. И тогда может и отладчик включаться (но лучше — в неинтерактивном режиме, а, например, со скриптами на точки останова).

S>Остается позавидовать тем, у кого в Debug режиме производительность достаточная для решения их задач. И кто готов ходить по граблям "в Debug все работает, а в Release какие-то странные вещи происходят" просто потому, что без отладчика ни на что не годен.

Какие у вас основания для подобных домыслов, кроме собственной буйной фантазии?

N>>Во-вторых, в остальном умные вещи пишете, а тут — такую древнюю наркоманию.

S>Я тут уже после первого упоминания об отладке реалтайм кода в отладчике перестал всерьез что-либо писать.

Ну вот очень жаль, что вы в ответ на вполне разумные вещи включили дурочку.
The God is real, unless declared integer.
Re[6]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.11.20 16:32
Оценка: +1
Здравствуйте, so5team, Вы писали:

S>Все это не может не внести значимый оверхед по сравнению с Release режимом.


Так оно и вносит, с этим никто не спорит. Вы кому возражаете-то?

Из того, что код реалтаймовый, ни разу не вытекает, что он со всей этой отладочной лабудой непременно потеряет возможность успевать за процессом. Хотя и такое бывает.

S>В Debug сборке 50K req/s, в Release 150K req/s. Ну вот нельзя всерьез говорить о важности скорости в Debug-е, если просадка в 3 раза на ровном месте.


Каким образом это может автоматически снять вопрос о важности скорости? Если для задач, которые решает ваш код, достаточно обрабатывать, например, 20K req/s, то какие проблемы может создать отсутствие оптимизации в отладочных сборках? А если требуется обрабатывать 200K req/s, то этот код вообще не годится, хоть отладочный, хоть релизный. Где логика?

S>Изрядная часть реально сложных багов возникает на максимальных нагрузках при максимальной производительности. Когда минимальные задержки и срабатывают сценарии, о которых разработчик даже никогда не задумывался, а в Debug режиме даже близко к ним подойти не может, потому что скорости тупо не хватает для повторения. Могу только пожелать удачи в борьбе с такими проблемами посредством пошаговой отладки в отладчике.


Поздравляю, Вы сперва откуда-то взяли, что никто, кроме Вас, не знает о таких сложных багах и не умеет с ними бороться, а затем принялись активно спорить с воображаемым оппонентом. А ведь Вам прямо и подробно описали, что как раз для подобных случаев и нужны выборочные оптимизации, а не тупое деление на "debug" и "release".

S>сейчас время от времени приходится иметь дело с потоками событий в десятки тысяч в секунду. И когда кто-то мне начинает вещать про полезность отладчика в таких условиях


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

S>>Ассерты в релизе?


ЕМ>Почему нет?


По определению.

N>>>Какая-то должна начать писать логи и трейсы вместо полного вышибания.

S>>Опять же, это часть логики, от Debug/Release не зависит.

ЕМ>Почему? Даже если конфигураций всего две (Debug/Release), то какая-то регистрация может быть безусловной, а остальная добавляться только в Debug. Но еще лучше вынести все это в независимые параметры. Тогда любую конфигурацию можно собрать с любым набором параметров, и от Debug/Release остаются только имена.


Опять же, по определению. Если у вас больше конфигураций сборки, нежели Debug и Release, то тогда и говорите о других конфигурациях, а не о Debug и Release.

S>>я говорю лишь о том, что когда ставят вопрос о максимальной скорости, то показатели заведомо заторможенного кода не должны никого волновать.


ЕМ>Кроме черного и белого, есть даже оттенки серого, не говоря уже о других цветах.


Это в разговоре о скорости кода у вас есть оттенки? Ну ОК, чего только не бывает.

ЕМ>WinDbg выполняет перехват и простые скрипты за доли миллисекунды. Если Вы не считаете это реалтаймом, то хотелось бы услышать доводы, отличные от сугубо личного мнения.


Ну а я бы еще послушал афигительные истории про пошаговую отладку в реал-тайме. Веселит, знаете ли.
Re[9]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 07.11.20 07:49
Оценка: +1
Здравствуйте, netch80, Вы писали:

S>>Например то, что 95% кода от меня не зависит. Если кто-то хочет вручную управлять ассертами в потрохах STL или Asio -- флаг в руки.


N>При необходимости и это делается. Хотя, да, лучше обойтись внешними средствами.

N>Но даже в той же STL есть vector::operator[], а есть vector::at.

Выбор между operator[] и at для vector вообще лежит вне деления на Debug/Release.

N>>>Те же ассерты — какая-то часть из них должна остаться и в релизе.

S>>Ассерты в релизе? Это либо какая-то лютая хрень, либо не ассерты, а часть логики кода (например, часть defensive programming) которая отвечает за проверку контрактов и/или инвариантов. Но эта часть не является зависящими от NDEBUG ассертами.

N>Ну а кто вам сказал, что все ассерты обязаны зависеть от NDEBUG?

N>В одной задаче у меня было 4 уровня включения этих ассертов.

Тогда вы assert-ами называете свой велосипед, а не штатный assert.

N>>>Какая-то должна начать писать логи и трейсы вместо полного вышибания.

S>>Опять же, это часть логики, от Debug/Release не зависит.

N>Это всё то же: та часть кода, которая выполняет не целевую логику, а защитную. Стандартный assert() это точно так же часть defensive programming, как и любые самопальные аналоги.


У меня совершенно другое представление о defensive programming. Я привык думать, что defensive programming -- это набор техник и приемов, которые обеспечивают защиту от работы с некорректными значениями, нарушенными контрактами и инвариантами. Причем защита эта не зависит от того, компилируемся ли мы в Debug или в Release, эта защита присутствует в итоговом коде приложения.

Приемы же, которые используются на этапе отладки и которые изымаются из итогового кода -- это отладочные средства. К коим и относится штатный assert.

Если для вас defensive programming -- это что-то другое, то OK. Значит мы спорим не договорившись об определениях.

N>Кстати, не подскажете, в чьей STL и почему есть именно те assertʼы, которые зависят от NDEBUG? MSVC не предлагать.


Не подскажу.

N>Вам Евгений уже несколько раз сказал: есть то, что зовётся good enough — код успевает (например, надо скормить следующую порцию звука за 10 мс — он кормит). Но есть и возможность лучшего результата, и если она достигается за 2 мс без особого напряга — это ещё лучше.

N>Граница будет проходить там, где мы вступаем в зону недопустимых оптимизаций.

Евгений, видимо, существует в очень комфортных условиях. Скажем, у него время отклика 10ms и его код (причем, скорее всего, только его, без каких-либо внешних зависимостей) даже в Debug сборке успевает в это время уложиться.

Повторюсь: этому можно только позавидовать. Вопрос в том, что он будет делать, если у него оптимизированный код будет с трудом в 10ms укладываться. Он все еще продолжит рассуждать о важности скорости в Debug варианте?

S>>Если у вас есть примеры того, где важна максимальная скорость кода, собранного в Debug режиме, то с интересом послушаю.


N>Если вы перестанете думать только про Debug и Release, то можно обсудить. Но пока у вас только чёрное и белое — я воздержусь.


Не я завел разговор о Debug сборках. А, так уж получается, что Debug и Release -- это вполне себе устоявшиеся понятия. Вплоть до того, что на том же MSVC в Debug и Release вы вынуждены линковаться к разным версиям runtime-библиотек.

Но, я так понимаю, что волнительных историй на счет скорости именно в Debug не будет.

Так-то и я могу рассказать, что временами собираю код с -O2 и -g для целей профилирования.
Re[9]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 08:10
Оценка: +1
Здравствуйте, netch80, Вы писали:

N>Это очень просто. Выкиньте из головы прибитые там гвоздями представления про универсальный подход по опциям сборки на весь код. Дальше пойдёт легче.


а зачем?
если существующий подход нормально работает и используемые средства разработки под него заточены.
что именно мы получаем от придуманных нами каких-то дополнительных уровней отладки/сборки?
Re[19]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 13:16
Оценка: +1
Здравствуйте, netch80, Вы писали:

NB>>нет никаких "правильная"/"неправильная". есть просто разное назначение.

NB>>и в сборке Debug критерий производительности играет не очень важную роль.

N>Ну вот у вас "не очень важную".

N>А so5team@ заглючило на том, что якобы вообще тут производительность не имеет значения, и не разглючивает.

ну, для меня тоже не совсем понято не желание что-то использовать только по той причине, что в дебаг режиме используемый компилятор не делает NRVO
Отредактировано 07.11.2020 16:10 night beast . Предыдущая версия . Еще …
Отредактировано 07.11.2020 16:08 night beast . Предыдущая версия .
Отредактировано 07.11.2020 13:20 night beast . Предыдущая версия .
Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция 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: Возврат ошибок из недр вложенных вызовов
От: 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[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[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[3]: Возврат ошибок из недр вложенных вызовов
От: Muxa  
Дата: 05.11.20 16:29
Оценка:
KP>>Не очень понял, чем исключения для такой цели плохи.
ЕМ>Я ж специально пояснил, что не все отказы функций нижнего уровня являются фатальными для верхних. В ряде случаев нет другого способа что-то сделать, кроме как тупо перебрать несколько десятков-сотен наборов параметров, последовательно вызывая функции нижнего уровня с каждым из них.

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

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


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

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


А если вдруг возвращает "устройство отключено", "отказ в доступе" и т.п., то это уже нештатная ситуация, о которой нужно сообщить именно на самый верх.
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>Реальное время -- оно же такое, не критичное.


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

M>Чот не похоже что это будет вызываться сотни тысяч раз в секунду.


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

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


Ну вот разве только обычными кодами возврата сигнализировать "нефатальные" результаты, а для "фатальных" бросать исключения...

Кстати, C++RT для виндового ядра, судя по всему, до сих пор не поддерживает плюсовые исключения. Но в ядерном коде я пока обхожусь обычными результатами.
Re[3]: Возврат ошибок из недр вложенных вызовов
От: alexanderfedin США http://alexander-fedin.pixels.com/
Дата: 05.11.20 22:27
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Я ж специально пояснил, что не все отказы функций нижнего уровня являются фатальными для верхних. В ряде случаев нет другого способа что-то сделать, кроме как тупо перебрать несколько десятков-сотен наборов параметров, последовательно вызывая функции нижнего уровня с каждым из них. Если при каждом вызове функция будет выбрасывать исключение, то накладные расходы станут чрезмерными, а главное — слабопредсказуемыми. Некоторые функции вызываются в достаточно жестком (максимум сотни микросекунд на всю обработку) реалтайме, поэтому исключения там допустимы лишь в фатальных случаях.

У IBM в их библиотеке поддержки юникода было так:
void foo(int *error, char a, float b, short c)
{
   if (*error) return;
   // do some stuff
   if (/* condition */)
   {
      *error = ERROR_IO_FAIL;
      return;
   }
   // do some stuff
}

void bar(int *error, char a)
{
   if (*error) return;
   // do some stuff
   foo(error, a, 2.7f, 123); if (*error) return;
   if (/* condition */)
   {
      *error = ERROR_IO_FAIL;
      return;
   }
   foo(error, a, 3.14f, 456); if (*error) return;
   // do some stuff
}

void main()
{
   int error;
   // do some stuff
   bar(&error, 'X'); if (*error) return;
   bar(&error, 'Y'); if (*error) return;
   // do some stuff
}
Respectfully,
Alexander Fedin.
Re: Возврат ошибок из недр вложенных вызовов
От: bnk СССР http://unmanagedvisio.com/
Дата: 05.11.20 23:06
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Типичная ситуация: функция верхнего уровня вызывает функцию более низкого уровня, та — следующую и т.п., и где-то на N-м уровне очередной вызов возвращает ошибку. Если это что-то уникальное, то можно вернуть наверх (хоть через обычные return, хоть через исключения) уникальный код и/или описание. Но если ошибка общего характера (нехватка ресурсов, отказ в доступе, разрыв соединения и т.п.), то неплохо бы вернуть наверх более подробную информацию, которую можно показать пользователю, чтобы он имел более-менее адекватное представление о проблеме.


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


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


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


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


Если исключения слишком дороги, то вроде ничего кроме кода возврата не остается.
Как вариант видел много где, в том числе у Microsoft, паттерн "on error goto hell" для всякой низкоуровневой фигни, это код возврата с goto на очистку. пример

А так в нормальной практике это конечно исключения.
Вроде правила простые — если обработчик знает, что делать с исключением — обрабатывает, иначе пропускает наверх, возможно дописывая к нему какую-то полезную инфу (уточнение).
Отредактировано 05.11.2020 23:14 bnk . Предыдущая версия . Еще …
Отредактировано 05.11.2020 23:12 bnk . Предыдущая версия .
Re[3]: Возврат ошибок из недр вложенных вызовов
От: varenikAA  
Дата: 06.11.20 01:15
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, varenikAA, Вы писали:


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


ЕМ>В лиспах вопрос быстродействия и накладных расходов стоит на самых последних позициях.


Ну, вот тут показано, что возможна Реализация Common Lisp Condition System на C#
Что если реализовать на плюсах? Сам я в них ни бум-бум.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[3]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.11.20 06:46
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

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


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


Хранишь под таким указателем созданный объект ошибки. Набиваешь параметрами. Даже при проблемах с RVO максимум цены — это увеличение и уменьшение счётчика ссылок.

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

N>>Отлично в них с TLS.
ЕМ>Во всех?

В названных — да. Если у вас есть причины сомневаться — опубликуйте их.
Уточнение: я про юзерленд. В ядре TLS нет совсем, и не будет.
The God is real, unless declared integer.
Re[3]: Возврат ошибок из недр вложенных вызовов
От: sergii.p  
Дата: 06.11.20 07:17
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

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


std::expected можно заменить обычным
template<typename Res> 
using expected = std::variant<Res, std::exception_ptr>;


монадическая обработка ошибок тоже наворачивается легко

template<typename Functor>
struct action { Functor f; }

template<typename Functor>
auto map(Functor&& f)
{
    return action{std::forward<Functor>(f)};
}

template<typename Res> 
auto operator | (expected<Res> const& ex, action const& a)
{
    using Ret = decltype(a.f(std::declval<Res>()));
    return std::holds_alternative<Res>(ex)
        ? expected<Ret>{ a.f(std::get<0>(ex)) }
        : expected<Ret>{ std::get<1>(ex) };
}

// использование
const bool isEmptyLogin = getUserByHttp()
    | map(getLoginByUser)
    | map([](auto const& v) { return v.empty(); })
Re[4]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 06.11.20 07:28
Оценка:
Здравствуйте, sergii.p, Вы писали:

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


SP>std::expected можно заменить обычным

SP>
SP>template<typename Res> 
SP>using expected = std::variant<Res, std::exception_ptr>;
SP>


К сожалению, expected не выражается через variant, если и нормальный результат, и код ошибки представляется одним и тем же типом. Например, int-ом:
expected<int, int> do_something() {...}

Ну и плюс удобный (в отсутствии паттерн-матчинга в C++) интерфейс expected (operator bool, operator*, error()), плюс полезная свободная функция make_unexpected.
Re[5]: Возврат ошибок из недр вложенных вызовов
От: sergii.p  
Дата: 06.11.20 08:19
Оценка:
Здравствуйте, so5team, Вы писали:

S>К сожалению, expected не выражается через variant, если и нормальный результат, и код ошибки представляется одним и тем же типом. Например, int-ом:

S>
S>expected<int, int> do_something() {...}
S>


вариант 1: можно инициализировать через in_place_index
вариант 2: использовать для ошибки свой враппер

template<typename T>
struct error
{
    T val;
}

template<typename Res, typename Err = std::exception_ptr> expected = std::variant<Res, error<Err>>;



S>Ну и плюс удобный (в отсутствии паттерн-матчинга в C++) интерфейс expected (operator bool, operator*, error()), плюс полезная свободная функция make_unexpected.


всё это реализуется свободными функциями по мере надобности. Сам же Страуструп из core guidelines вещает, что предпочитайте свободные функции
Вообще, конечно, вы отчасти правы.
Если хочется, можно пойти дальше. Использовать union.
template<typename Val, typename Err>
struct expected_helper
{
    union
    {
    Val v;
    Err e;
    }
    bool isError;
}

и уже писать свой класс expected со всякими прочими операторами.
Re[6]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 06.11.20 08:39
Оценка:
Здравствуйте, sergii.p, Вы писали:

SP>Если хочется, можно пойти дальше. Использовать union.

SP>
SP>template<typename Val, typename Err>
SP>struct expected_helper
SP>{
SP>    union
SP>    {
SP>    Val v;
SP>    Err e;
SP>    }
SP>    bool isError;
SP>}
SP>


И решать вопросы с типами Val/Err, у которых нетривиальные деструкторы и/или конструкторы/операторы копирования/перемещения.

SP>и уже писать свой класс expected со всякими прочими операторами.


В библиотеках вроде expected_lite это все уже сделано. И вряд ли ТС сможет сделать это лучше.
Re[2]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.11.20 08:42
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>Как вариант видел много где, в том числе у Microsoft, паттерн "on error goto hell" для всякой низкоуровневой фигни, это код возврата с goto на очистку.


Это работает в рамках отдельной функции — я для этого использую do { } while (false) с break, и давно зол на MS за то, что их __try/__finally работает только через SEH.
Re[3]: Возврат ошибок из недр вложенных вызовов
От: Qulac Россия  
Дата: 06.11.20 09:23
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, kaa.python, Вы писали:


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


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


А тут нет "серебренной пули", каждый случай нужно рассматривать отдельно, часто лучше всего это подойти к проблеме чисто формально, т.е. если у нас система может реагировать на ошибки двумя способами, то делаем два исключения, что бы выбор действия происходил в блоке try — catch
Программа – это мысли спрессованные в код
Re[3]: Возврат ошибок из недр вложенных вызовов
От: reversecode google
Дата: 06.11.20 10:23
Оценка:
ЕМ>А что нового изучать, когда я до сих пор делаю в основном ядерный код?

http://www.zer0mem.sk/?p=517
Re[3]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.11.20 10:30
Оценка:
Здравствуйте, netch80, Вы писали:

N>И режимы должны выставляться не для кода в целом, а гранулироваться до файла, функции или даже блока кода. Это на юзерленде, но к ядру может ещё больше относиться. Конечно, отрасль страшно консервативна и будет ещё 20 лет тормозить


Самое странное, когда тормозят те части отрасли, которые работают прежде всего сами на себя. Вот GNU делает gcc, которым собирается, в том числе, и линуксовое ядро — и наделали оптимизаций на любой вкус и цвет. А в MS VC++ периодически натыкаюсь на очевидные ляпы вроде этого
Автор: Евгений Музыченко
Дата: 25.12.19
. Но тут у них, безусловно, нет обратной связи — само ядро до сих пор на чистом C, и только отдельные модули на C++, они пока не роялят.

N>если вы где-то не видите возможности регулировать хотя бы оптимизации под конкретную функцию — самое время начинать бить ногами, чтобы авторы компилятора/среды проснулись.


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

_>Логи.


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

Сделаю, наверное, подобную штуку в универсальном виде, чтобы можно было использовать и для других целей. Например, некоторые мои драйверы работают через системные обертки, которые получают запрос от клиента, затем вызывают отдельные функции драйвера. Периодически приходится корректировать работу этих оберток, перехватывая запрос на входе и запоминая его параметры в глобальной структуре, чтобы достать потом внутри своей функции. Это обеспечивает передачу снаружи внутрь, а если сделать в общем виде, то и в любую сторону.
Re[4]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.11.20 10:50
Оценка:
Здравствуйте, netch80, Вы писали:

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

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

N>Хранишь под таким указателем созданный объект ошибки. Набиваешь параметрами. Даже при проблемах с RVO максимум цены — это увеличение и уменьшение счётчика ссылок.


Тогда возникает вопрос, где и когда создавать такой объект. Если снаружи, то его нужно как-то передать внутрь — или в параметрах каждой функции, или в какой-нибудь глобальной структуре. Если внутри, то не получится, как минимум, сообщить наружу о том, для чего именно не хватило динамической памяти. Хотя в современных реалиях вероятность нехватки памяти для работы моего кода можно считать строго нулевой.

N>Уточнение: я про юзерленд. В ядре TLS нет совсем, и не будет.


Строго говоря, в ядре нет проблем сделать TLS для собственных потоков, создаваемых модулем ядра. Проблема только с клиентскими потоками, вызывающими модуль снаружи.
Re[4]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.11.20 10:56
Оценка:
Здравствуйте, reversecode, Вы писали:

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


R>http://www.zer0mem.sk/?p=517


Что именно нового для себя я мог бы узнать из этой статьи?
Re: Возврат ошибок из недр вложенных вызовов
От: edton  
Дата: 06.11.20 11:21
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ> то неплохо бы вернуть наверх более подробную информацию, которую можно показать пользователю, чтобы он имел более-менее адекватное представление о проблеме.


"Подробная информация, которую можно показать пользователю" в целом ограничена количеством заранее заготовленных строк, которые мы показываем в messagebox или еще где, даже если это строки вида "Не удалось открыть файл %s в папке %s потому, что %s" Показывать пользователю что то более сложное чаще всего (от софта и аудитории конечно зависит) не имеет смысла. Пользователю ведь зачем это сообщение — или чтобы разобраться самому или отправить потенциальный баг репорт разработчику. Если речь о том, чтобы разобраться самому пользователю, то даже большинство ошибок системных вызовов можно свести к нескольким десяткам заготовленных строк с высокой вероятностью, что они более или менее опишут проблему, и самое главное помогут ее решить пользователю.
Re[2]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.11.20 11:52
Оценка:
Здравствуйте, edton, Вы писали:

E>"Подробная информация, которую можно показать пользователю" в целом ограничена количеством заранее заготовленных строк, которые мы показываем в messagebox или еще где, даже если это строки вида "Не удалось открыть файл %s в папке %s потому, что %s"


Совершенно верно. Вот как раз эти %s и нужно вернуть изнутри наружу. Сама форматная строка вполне может однозначно определяться кодом ошибки.
Re[6]: Возврат ошибок из недр вложенных вызовов
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 06.11.20 16:12
Оценка:
Здравствуйте, so5team, Вы писали:

S>Изрядная часть реально сложных багов возникает на максимальных нагрузках при максимальной производительности. Когда минимальные задержки и срабатывают сценарии, о которых разработчик даже никогда не задумывался, а в Debug режиме даже близко к ним подойти не может, потому что скорости тупо не хватает для повторения. Могу только пожелать удачи в борьбе с такими проблемами посредством пошаговой отладки в отладчике.


Бывает так, что в релизе все (в смысле многопоточности) успевают проскочить через проблемное место, а в debug-сборке (именно из за тормозов) не успевают.

---
Бывает еще, что неделю гоняешь автоматизированные тесты — все ок. А потом, случайно решишь повозиться руками — а оно .....ля оказывается валится.

---
В общем, не все так однозначно
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[6]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.11.20 16:25
Оценка:
Здравствуйте, so5team, Вы писали:

N>>>>Во-первых, как уже сказано, и в отладочном режиме скорость может быть важна, и критически важна. И тогда может и отладчик включаться (но лучше — в неинтерактивном режиме, а, например, со скриптами на точки останова).

S>>>Остается позавидовать тем, у кого в Debug режиме производительность достаточная для решения их задач. И кто готов ходить по граблям "в Debug все работает, а в Release какие-то странные вещи происходят" просто потому, что без отладчика ни на что не годен.

N>>Какие у вас основания для подобных домыслов, кроме собственной буйной фантазии?


S>Ну давайте посмотрим. Режим Debug -- это ведь не только отсутствие оптимизаций со стороны компилятора. Это ведь и выполнение assert-ов, которые могут быть в изобилии разборосаны в коде (причем не столько в вашем собственном, сколько в коде использованных вами сторонних библиотек) + (возможно) дополнительные куски проверок и других форм defensive programming, которые включаются только в Debug режиме (опять же, больше в сторонних библиотеках) + (возможно) специальные отладочные фокусы в STL (вроде STL от MS с дополнительными проверками в итераторах) + (возможно) специальные версии new/delete, которые выполняют дополнительные проверки и/или несколько иначе располагают данные в памяти (добавляют специальные проверочные фрагменты до/после выделенного блока). Все это не может не внести значимый оверхед по сравнению с Release режимом.


S>Просто для иллюстрации: специально после того как утром прочел ваш ответ прогнал один из простеньких бенчмарков нашего RESTinio. В Debug сборке 50K req/s, в Release 150K req/s. Ну вот нельзя всерьез говорить о важности скорости в Debug-е, если просадка в 3 раза на ровном месте.


Вот! Вы только подтвердили, что я говорю.

Вы выставили сами себе два режима — debug и release. Вы навесили на них кучу всякого. Типа, debug у вас с ассертами, а релиз — без. Дебаг без оптимизации, а релиз — с максимальной оптимизацией, и тому подобное. Я понимаю, что в какой-то мере это определяется внешними условиями типа

>> роде STL от MS с дополнительными проверками в итераторах) + (возможно) специальные версии new/delete


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

Есть сравнение по этому поводу, которому уже надцать лет, но я забыл автора: подобные методы это всё равно что сначала вести автомобиль со скоростью пешехода, а затем гонять на всех газах, не пристёгиваясь. Вы вот ровно такого горе-водителя и описываете.

S>Изрядная часть реально сложных багов возникает на максимальных нагрузках при максимальной производительности. Когда минимальные задержки и срабатывают сценарии, о которых разработчик даже никогда не задумывался, а в Debug режиме даже близко к ним подойти не может, потому что скорости тупо не хватает для повторения. Могу только пожелать удачи в борьбе с такими проблемами посредством пошаговой отладки в отладчике.


И ещё раз: откуда вы взяли про пошаговую отладку? Ваши представления об отладчиках застыли на уровне каменного века? Ну так узнайте хоть что-то про современные инструменты.
В качестве простейшего примера: отладчики могут поддерживать скрипты точек останова, которые будут писать, если нужно, детали обстановки, или модифицировать её по условию, и тут же запускать код дальше.
Да даже дополнительные логи без перекомпиляции — уже прогресс — и это делается без проблем.

N>>>>Во-вторых, в остальном умные вещи пишете, а тут — такую древнюю наркоманию.

S>>>Я тут уже после первого упоминания об отладке реалтайм кода в отладчике перестал всерьез что-либо писать.
N>>Ну вот очень жаль, что вы в ответ на вполне разумные вещи включили дурочку.
S>У меня был опыт с реальным временем в прошлом, а сейчас время от времени приходится иметь дело с потоками событий в десятки тысяч в секунду. И когда кто-то мне начинает вещать про полезность отладчика в таких условиях, то я снимаю лапшу с ушей и, если есть настроение, начинаю прикалываться над расказчиками этих удивительных историй. Вот как в данном случае.

Вся ваша "лапша" на ушах — собственного изготовления, и таки да, чтобы начать слушать, вам надо её снять с ушей.
The God is real, unless declared integer.
Re[7]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.11.20 16:39
Оценка:
Здравствуйте, netch80, Вы писали:

N>И ещё раз: откуда вы взяли про пошаговую отладку?


Так это я о ней писал. В определенных условиях она наиболее удобна.
Re[8]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.11.20 16:47
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

N>>И ещё раз: откуда вы взяли про пошаговую отладку?


ЕМ>Так это я о ней писал. В определенных условиях она наиболее удобна.


Вот именно, что у тебя "в определённых условиях" и ты знаешь, что бывает иначе. А so5team вообще никакого больше варианта не слышит.
The God is real, unless declared integer.
Re[7]: Возврат ошибок из недр вложенных вызовов
От: night beast СССР  
Дата: 06.11.20 17:01
Оценка:
Здравствуйте, netch80, Вы писали:

N>И ещё раз: откуда вы взяли про пошаговую отладку? Ваши представления об отладчиках застыли на уровне каменного века? Ну так узнайте хоть что-то про современные инструменты.

N>В качестве простейшего примера: отладчики могут поддерживать скрипты точек останова, которые будут писать, если нужно, детали обстановки, или модифицировать её по условию, и тут же запускать код дальше.
N>Да даже дополнительные логи без перекомпиляции — уже прогресс — и это делается без проблем.

о каких инструментах речь?
если о студии, то там это очень сильно тормозит исполнение программы (порою бывает проще вставить явный вывод или проверку условий)
Re[8]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.11.20 17:14
Оценка:
Здравствуйте, night beast, Вы писали:

N>>И ещё раз: откуда вы взяли про пошаговую отладку? Ваши представления об отладчиках застыли на уровне каменного века? Ну так узнайте хоть что-то про современные инструменты.

N>>В качестве простейшего примера: отладчики могут поддерживать скрипты точек останова, которые будут писать, если нужно, детали обстановки, или модифицировать её по условию, и тут же запускать код дальше.
N>>Да даже дополнительные логи без перекомпиляции — уже прогресс — и это делается без проблем.

NB>о каких инструментах речь?

NB>если о студии, то там это очень сильно тормозит исполнение программы (порою бывает проще вставить явный вывод или проверку условий)

Не, ну с перекомпиляцией, понятно, почти наверняка быстрее бегать будет (а вот можно ли так перекомпилировать и сколько это займёт — тут и начинаются загвоздки). Но всё равно даже с остановками и переключениями быстрее, чем человек — и это уже то, о чём я говорю.
Виндовую специфику я тут не знаю. Под Linux или чем-то похожим мне нормально сработало.
The God is real, unless declared integer.
Отредактировано 06.11.2020 17:15 netch80 . Предыдущая версия .
Re[7]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 06.11.20 17:18
Оценка:
Здравствуйте, netch80, Вы писали:

N>но зачем вы целиком этому подчиняетесь? Что мешает включить голову и самому управлять, что нужно?


Например то, что 95% кода от меня не зависит. Если кто-то хочет вручную управлять ассертами в потрохах STL или Asio -- флаг в руки.

N>Те же ассерты — какая-то часть из них должна остаться и в релизе.


Ассерты в релизе? Это либо какая-то лютая хрень, либо не ассерты, а часть логики кода (например, часть defensive programming) которая отвечает за проверку контрактов и/или инвариантов. Но эта часть не является зависящими от NDEBUG ассертами.

N>Какая-то должна начать писать логи и трейсы вместо полного вышибания.


Опять же, это часть логики, от Debug/Release не зависит.

N>Есть сравнение по этому поводу, которому уже надцать лет, но я забыл автора: подобные методы это всё равно что сначала вести автомобиль со скоростью пешехода, а затем гонять на всех газах, не пристёгиваясь. Вы вот ровно такого горе-водителя и описываете.


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

Если у вас есть примеры того, где важна максимальная скорость кода, собранного в Debug режиме, то с интересом послушаю.

N>И ещё раз: откуда вы взяли про пошаговую отладку? Ваши представления об отладчиках застыли на уровне каменного века? Ну так узнайте хоть что-то про современные инструменты.


Вывел это из контекста разговора с ТС-ом.

N>В качестве простейшего примера: отладчики могут поддерживать скрипты точек останова, которые будут писать, если нужно, детали обстановки, или модифицировать её по условию, и тут же запускать код дальше.


Если ТС апеллирует к реал-тайму, то даже такие продвинутые отладчики в условиях реал-тайма идут лесом. Ну или у реал-тайма там время отклика секундное.
Re[7]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 06.11.20 17:26
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Так оно и вносит, с этим никто не спорит. Вы кому возражаете-то?


Возражения вы где увидели?

ЕМ>Из того, что код реалтаймовый, ни разу не вытекает, что он со всей этой отладочной лабудой непременно потеряет возможность успевать за процессом. Хотя и такое бывает.


Если у вас скорости такие, что вы укладываетесь в дедлайны даже в Debug режиме, то ваша трогательная забота о накладных расходах выглядит весьма странно.

S>>В Debug сборке 50K req/s, в Release 150K req/s. Ну вот нельзя всерьез говорить о важности скорости в Debug-е, если просадка в 3 раза на ровном месте.


ЕМ>Каким образом это может автоматически снять вопрос о важности скорости?


Автоматическим образом. Если вас устраивает 50K req/s, то заботиться о методах, которые позволяют достичь 150K req/s уже не нужно. В принципе. И освободившееся время/ресурсы можно потратить на что-то более полезное.

EM>А если требуется обрабатывать 200K req/s, то этот код вообще не годится, хоть отладочный, хоть релизный. Где логика?


В своих рассуждениях вы сами, пожалуйста, логику ищите. Я не собираюсь искать то, чего нет.
Re[8]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.11.20 17:31
Оценка:
Здравствуйте, night beast, Вы писали:

NB>о каких инструментах речь?


Под виндой в первую очередь — WinDbg. Он, конечно, неимоверно уродлив и местами глючен, но по мощности и гибкости ему равных нет.
Re[8]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.11.20 17:40
Оценка:
Здравствуйте, so5team, Вы писали:

S>Ассерты в релизе?


Почему нет?

S>Но эта часть не является зависящими от NDEBUG ассертами.


Правильно, она должна управляться отдельными параметрами.

N>>Какая-то должна начать писать логи и трейсы вместо полного вышибания.

S>Опять же, это часть логики, от Debug/Release не зависит.

Почему? Даже если конфигураций всего две (Debug/Release), то какая-то регистрация может быть безусловной, а остальная добавляться только в Debug. Но еще лучше вынести все это в независимые параметры. Тогда любую конфигурацию можно собрать с любым набором параметров, и от Debug/Release остаются только имена.

Параметры можно задавать в заголовках, если компилятор поддерживает управление нужной оптимизацией, или в Property Sheets для студии.

S>я говорю лишь о том, что когда ставят вопрос о максимальной скорости, то показатели заведомо заторможенного кода не должны никого волновать.


Кроме черного и белого, есть даже оттенки серого, не говоря уже о других цветах.

S>даже такие продвинутые отладчики в условиях реал-тайма идут лесом. Ну или у реал-тайма там время отклика секундное.


WinDbg выполняет перехват и простые скрипты за доли миллисекунды. Если Вы не считаете это реалтаймом, то хотелось бы услышать доводы, отличные от сугубо личного мнения.
Re[8]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.11.20 17:55
Оценка:
Здравствуйте, so5team, Вы писали:

S>Если у вас скорости такие, что вы укладываетесь в дедлайны даже в Debug режиме, то ваша трогательная забота о накладных расходах выглядит весьма странно.


Так я потому и укладываюсь, что всегда представляю, во что (хотя бы примерно) развернется та или иная языковая конструкция, периодически просматриваю ассемблерные листинги, принудительно включаю оптимизацию для некоторых фрагментов кода, в критичных местах автоматически проверяю время выполнения и т.п. В особо тяжелых режимах, само собой, и этого не хватает, но в основных — достаточно. А многократно избыточных накладных расходов я никогда не любил.

S>Если вас устраивает 50K req/s, то заботиться о методах, которые позволяют достичь 150K req/s уже не нужно. В принципе.


Да, если софт пишется только под конкретное железо (или вообще железо заказывается специально под софт). Но это, вообще-то, не норма.
Re[7]: Иллюстрация
От: so5team https://stiffstream.com
Дата: 07.11.20 06:38
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

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


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


Маленькая иллюстрация для тех, кого волнует максимальная скорость неоптимизированного кода: https://godbolt.org/z/dTf781
Шаблон tagged_scalar там сделан для того, чтобы при вызове конструктора limiter нельзя было перепутать аргументы, которые имеют один и тот же тип. Такой вот незамысловатый трюк для того, чтобы уменьшить количество ошибок в коде (ну нельзя же все на откуп assert-ам отдавать, ей Богу).

Желающие могут сравнить объем ассемблерного выхлопа при уровнях оптимизации -O0, -O1 и -O2.

Возможно, опыт Евгения Музыченко и netch80 на несколько порядков круче моего и они понимают в программировании сильно больше меня. Поэтому они видят какой-то глубокий смысл в том, чтобы оценивать скорость неоптимизированного C++ного кода. Но глядя на разницу между -O2 и другими уровнями оптимизации я лично этого смысла уловить не могу.
Re[8]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 07:29
Оценка:
Здравствуйте, so5team, Вы писали:

N>>но зачем вы целиком этому подчиняетесь? Что мешает включить голову и самому управлять, что нужно?

S>Например то, что 95% кода от меня не зависит. Если кто-то хочет вручную управлять ассертами в потрохах STL или Asio -- флаг в руки.

При необходимости и это делается. Хотя, да, лучше обойтись внешними средствами.
Но даже в той же STL есть vector::operator[], а есть vector::at.

N>>Те же ассерты — какая-то часть из них должна остаться и в релизе.

S>Ассерты в релизе? Это либо какая-то лютая хрень, либо не ассерты, а часть логики кода (например, часть defensive programming) которая отвечает за проверку контрактов и/или инвариантов. Но эта часть не является зависящими от NDEBUG ассертами.

Ну а кто вам сказал, что все ассерты обязаны зависеть от NDEBUG?
В одной задаче у меня было 4 уровня включения этих ассертов.

N>>Какая-то должна начать писать логи и трейсы вместо полного вышибания.

S>Опять же, это часть логики, от Debug/Release не зависит.

Это всё то же: та часть кода, которая выполняет не целевую логику, а защитную. Стандартный assert() это точно так же часть defensive programming, как и любые самопальные аналоги.

Кстати, не подскажете, в чьей STL и почему есть именно те assertʼы, которые зависят от NDEBUG? MSVC не предлагать.

N>>Есть сравнение по этому поводу, которому уже надцать лет, но я забыл автора: подобные методы это всё равно что сначала вести автомобиль со скоростью пешехода, а затем гонять на всех газах, не пристёгиваясь. Вы вот ровно такого горе-водителя и описываете.

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

Вам Евгений уже несколько раз сказал: есть то, что зовётся good enough — код успевает (например, надо скормить следующую порцию звука за 10 мс — он кормит). Но есть и возможность лучшего результата, и если она достигается за 2 мс без особого напряга — это ещё лучше.
Граница будет проходить там, где мы вступаем в зону недопустимых оптимизаций.
С тем, сколько в C/C++ разных undefined behavior, для меня нормально увидеть код, собранный вроде бы в релизе с -O1 (gcc) — когда большинство потенциально вредоносных оптимизаций ещё не включены: "зачем платить больше?"
Или вот я одному файлу при -O2 всё равно выставил -fno-strict-aliasing — там разборка структур по байтам, и не хочу, чтобы кто-то лажанулся и, сам того не заметив, дал сложные эффекты там, где их потом фиг поймаешь.

S>Если у вас есть примеры того, где важна максимальная скорость кода, собранного в Debug режиме, то с интересом послушаю.


Если вы перестанете думать только про Debug и Release, то можно обсудить. Но пока у вас только чёрное и белое — я воздержусь.

N>>В качестве простейшего примера: отладчики могут поддерживать скрипты точек останова, которые будут писать, если нужно, детали обстановки, или модифицировать её по условию, и тут же запускать код дальше.

S>Если ТС апеллирует к реал-тайму, то даже такие продвинутые отладчики в условиях реал-тайма идут лесом. Ну или у реал-тайма там время отклика секундное.

Миллисекундного достаточно. Это таки >90% обычного реалтайма в Windows/Linux/etc.
The God is real, unless declared integer.
Re[8]: Иллюстрация
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 07:46
Оценка:
Здравствуйте, so5team, Вы писали:

S>Маленькая иллюстрация для тех, кого волнует максимальная скорость неоптимизированного кода: https://godbolt.org/z/dTf781

S>Шаблон tagged_scalar там сделан для того, чтобы при вызове конструктора limiter нельзя было перепутать аргументы, которые имеют один и тот же тип. Такой вот незамысловатый трюк для того, чтобы уменьшить количество ошибок в коде (ну нельзя же все на откуп assert-ам отдавать, ей Богу).
S>Желающие могут сравнить объем ассемблерного выхлопа при уровнях оптимизации -O0, -O1 и -O2.

Спасибо, кэп.
Надеюсь, вы понимаете (или поймёте когда-нибудь), что это всё не имеет значения, например, в коде, который разбирает аргументы командной строки чего-то работающего заметное время: он может быть ещё хуже скомпилирован, да хоть встроенный Javascript вызывать — всё равно это доли секунды, и на общий результат не повлияет.

С другой стороны, никому вроде в голову не придёт писать для Debug на голых циклах там, где для Release применяют AVX интринсики — даже с учётом того, насколько на них сложнее писать, а потом понимать написанное.

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


Я не знаю, можно ли мой опыт оценивать "круче", это очень неконкретное понятие. Но я подозреваю, что 1) он заметно разнообразнее, 2) я кроме голого стажа ещё и делаю выводы из пройденного.
У меня бывали разные случаи. Грамотно написанная с нуля программа на питоне побивала в разы вроде бы хорошо оптимизированную на C++, потому что в последнем авторы увлеклись своими абстракциями по передаче данных между тем, что сейчас бы назвали акторами. Да, это было где-то в 2002 и после этого они очень быстро исправились (но поезд ушёл и наша соответствующая компонента так и сидит на питоне, хотя сейчас это уже точно гири на ногах). С другой стороны, для одной вычислительной задачи оказалось недостаточно игр с флагами оптимизации, и мы ещё несколько процентов выиграли на выборе компилятора для каждого файла (между gcc, icc и open64). И в обоих игра в бирюльки типа Debug/Release ничем не помогла, только сбивала бы с толку.

S> Поэтому они видят какой-то глубокий смысл в том, чтобы оценивать скорость неоптимизированного C++ного кода. Но глядя на разницу между -O2 и другими уровнями оптимизации я лично этого смысла уловить не могу.


Это очень просто. Выкиньте из головы прибитые там гвоздями представления про универсальный подход по опциям сборки на весь код. Дальше пойдёт легче.
The God is real, unless declared integer.
Re[9]: Иллюстрация
От: so5team https://stiffstream.com
Дата: 07.11.20 08:19
Оценка:
Здравствуйте, netch80, Вы писали:

N>Это очень просто. Выкиньте из головы прибитые там гвоздями представления про универсальный подход по опциям сборки на весь код.


Да без проблем. Пусть у нас есть приложение из модулей A, B и C. Каждый из них компилируется с разными уровнями оптимизации (и вообще с разными ключами компилятора, а может и даже разными компиляторами).

Если нас интересует производительность модуля C, то при наличии столь существенной разницы между -O0 и -O2 какой смысл оценивать скорость модуля C при -O0?

Может кто-то живет в условиях, когда -O2 запрещен на законадательном уровне?

N>Дальше пойдёт легче.


Сомнительно.
Re[10]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 08:19
Оценка:
Здравствуйте, so5team, Вы писали:

S>>>Например то, что 95% кода от меня не зависит. Если кто-то хочет вручную управлять ассертами в потрохах STL или Asio -- флаг в руки.

N>>При необходимости и это делается. Хотя, да, лучше обойтись внешними средствами.
N>>Но даже в той же STL есть vector::operator[], а есть vector::at.
S>Выбор между operator[] и at для vector вообще лежит вне деления на Debug/Release.

И в надцатый раз — это вам так кажется, пока для вас эти два слова это нечто в настройках сборки, правилами которой вы не управляете.
Сделайте свой враппер, который выбирает между ними — и получите управляемый выбор.

N>>Ну а кто вам сказал, что все ассерты обязаны зависеть от NDEBUG?

N>>В одной задаче у меня было 4 уровня включения этих ассертов.
S>Тогда вы assert-ами называете свой велосипед, а не штатный assert.

Я называю этим весь комплект защитных средств системы "если условие не выполнилось, тут не продолжаем", и это правильнее.

N>>Это всё то же: та часть кода, которая выполняет не целевую логику, а защитную. Стандартный assert() это точно так же часть defensive programming, как и любые самопальные аналоги.

S>У меня совершенно другое представление о defensive programming. Я привык думать, что defensive programming -- это набор техник и приемов, которые обеспечивают защиту от работы с некорректными значениями, нарушенными контрактами и инвариантами. Причем защита эта не зависит от того, компилируемся ли мы в Debug или в Release, эта защита присутствует в итоговом коде приложения.

S>Приемы же, которые используются на этапе отладки и которые изымаются из итогового кода -- это отладочные средства. К коим и относится штатный assert.


S>Если для вас defensive programming -- это что-то другое, то OK. Значит мы спорим не договорившись об определениях.


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

N>>Вам Евгений уже несколько раз сказал: есть то, что зовётся good enough — код успевает (например, надо скормить следующую порцию звука за 10 мс — он кормит). Но есть и возможность лучшего результата, и если она достигается за 2 мс без особого напряга — это ещё лучше.

N>>Граница будет проходить там, где мы вступаем в зону недопустимых оптимизаций.
S>Евгений, видимо, существует в очень комфортных условиях. Скажем, у него время отклика 10ms и его код (причем, скорее всего, только его, без каких-либо внешних зависимостей) даже в Debug сборке успевает в это время уложиться.

Пусть сам расскажет. Я пример про 10 мс дал только навскидку. Может, у него 10 мкс. Может, ему меньше чем аналог -Og не подходит.

S>Повторюсь: этому можно только позавидовать. Вопрос в том, что он будет делать, если у него оптимизированный код будет с трудом в 10ms укладываться. Он все еще продолжит рассуждать о важности скорости в Debug варианте?


Вполне возможно. Можно испытать корректность в условиях, где пойдёт 20 или 50 мс, и потом ужесточить до реальных.

S>Но, я так понимаю, что волнительных историй на счет скорости именно в Debug не будет.


Вы ждёте "волнительных историй" вместо обсуждения по сути... Ну ждите, ждите.
The God is real, unless declared integer.
Re[11]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 07.11.20 08:35
Оценка:
Здравствуйте, netch80, Вы писали:

N>>>Но даже в той же STL есть vector::operator[], а есть vector::at.

S>>Выбор между operator[] и at для vector вообще лежит вне деления на Debug/Release.

N>И в надцатый раз — это вам так кажется, пока для вас эти два слова это нечто в настройках сборки, правилами которой вы не управляете.

N>Сделайте свой враппер, который выбирает между ними — и получите управляемый выбор.

Простите, но либо вы выбрали крайне неудачный пример, либо говорите какую-то ерунду.

Различия в семантике operator[] и at для std::vector определены на уровне стандарта. Так, at гарантированно выполняет проверки индекса и бросает исключения (вне зависимости от режима сборки), тогда как operator[] эти проверки не делает. И последствия передачи в at/operator[] невалидного индекса принципиально разные. Соответственно, и сфера применения у них разные. Так, at применяется для обеспечения защиты в коде, а operator[] для получения максимальной производительности ценой небезопасности.

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

S>>Тогда вы assert-ами называете свой велосипед, а не штатный assert.


N>Я называю этим весь комплект защитных средств системы "если условие не выполнилось, тут не продолжаем", и это правильнее.


Ну а я называю assert-ами именно штатные assert-ы, коие в избытке встречаются в коде тех или иных сторонних библиотек.

S>>Если для вас defensive programming -- это что-то другое, то OK. Значит мы спорим не договорившись об определениях.


N>Да, другое, и я это уже пару раз подчёркивал в предыдущих сообщениях — например, в том, как вы гоняете не пристегнувшись.


Аналогии -- это скользкий путь и он еще быстрее ведет к недопониманиям. Тем не менее, если уж показывать примеры на аналогиях, то в моем представлении defensive programming -- это когда вы вынуждены использовать ремень безопасности всегда, и во время учебы, и во время гонок, и во время обычных поездок. А вот применение того, что вы считаете assert-ами -- это избирательное использование ремней безопасности. Мол, при обучении (в Debug) ремни пристегиваем, а на гонке (в Release) -- нет.

Ну или дайте свое определение defensive programming, чтобы можно было понять о чем именно говорите вы.

N>Вы ждёте "волнительных историй" вместо обсуждения по сути... Ну ждите, ждите.


Да уже понятно, что их не будет. Всем можно расслабиться.
Re[10]: Иллюстрация
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 08:47
Оценка:
Здравствуйте, night beast, Вы писали:

N>>Это очень просто. Выкиньте из головы прибитые там гвоздями представления про универсальный подход по опциям сборки на весь код. Дальше пойдёт легче.


NB>а зачем?

NB>если существующий подход нормально работает и используемые средства разработки под него заточены.

В том и дело, что не работает он "нормально". Или, если для вас "нормально" это случай этого героя интернета, то да, нормально — но очень быстро выходишь за пределы таких ограничений.

NB>что именно мы получаем от придуманных нами каких-то дополнительных уровней отладки/сборки?


У вас некая очень толстая программа со своей историей, которую ведёт достаточно разнообразная команда. Вам надо её улучшить — например, есть конкретное место, где вам надо ускорить (неважно что — отрисовку на экране, расчёт зарплаты, парсинг сетевого запроса, etc.)
Вы определили те модули/функции/методы, где происходит критичное по скорости выполнение.
Вам надо в этих модулях:
1. Вылизать код относительно всех плюх.
2. Установить для него максимум оптимизации. При этом, так как оптимизации начинают вызывать предположения компилятора, которые не соответствуют предположениям программиста (вспоминаем весь комплект ужастиков про undefined behavior с переполнениями, алиасингом и т.п.) — это будет смесь визуальной верификации и запусков санитайзеров, пока не будет достигнуто выполнение, которое адекватно по скорости и не вызывает жалобы на проблемы кода.
3. Установить на всех границах этого кода контроль значений (который в идеале никогда не должен выключаться).
После этого быть всё равно готовым к тому, что что-то пойдёт не так и надо иметь базовую информацию хотя бы на уровне стейтрейсов и тех переменных, которые не убиты оптимизацией.

Остальной код, выполняющий тонны разнообразных сервисных функций, типа: передачу сообщений, чтение/запись файлов, общение с базой данных, общение с сетью и т.п. — занимает копейки относительно общих затрат времени, и пишется менее квалифицированными людьми.

В терминах gcc это значит, что критичные функции могут быть скомпилированы с -O2 или -O3, а для остальных достаточно -Og (чтобы совсем уж жуткие случаи типа гоняния одного значения по 5 регистрам или, как у so5team@, несвёрнутые шаблоны — были устранены) или даже -O0 (для половины кода). Причём ни в условном Release вам не нужна оптимизация всех 99% некритичного кода, ни в Debug вам нельзя понижать уровень оптимизации критичного кода ниже -O или даже -O2 — он просто не сможет выполнять свои функции.

При этом для всего кода программы вам нужна отладочная информация (даже если для типичного клиента она отделяется и поставляется отдельно, или вообще доступна только своему саппорту для анализа корок и трейсов).

В результате получается, что да, у вас может быть несколько режимов сборки. Может, хоть 100 (ну или предположим 128): в зависимости от того, подробности какого из критичных модулей вам важнее для конкретного испытания. И ни один из них не должен становиться каноническим Debug (-O0 -g), ни каноническим Release (-O2 или -O3, к которому кроме отсутствия -g добавлен ещё и strip на итоговые бинарники).
Даже если какой-то из этих уровней, для простоты и общности, будет иметь название Debug или Release, его суть будет заметно другой.
The God is real, unless declared integer.
Отредактировано 07.11.2020 8:54 netch80 . Предыдущая версия .
Re[12]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 08:59
Оценка:
Здравствуйте, so5team, Вы писали:

S>Различия в семантике operator[] и at для std::vector определены на уровне стандарта. Так, at гарантированно выполняет проверки индекса и бросает исключения (вне зависимости от режима сборки), тогда как operator[] эти проверки не делает. И последствия передачи в at/operator[] невалидного индекса принципиально разные. Соответственно, и сфера применения у них разные. Так, at применяется для обеспечения защиты в коде, а operator[] для получения максимальной производительности ценой небезопасности.

S>То, что operator[] в разных видах сборки может выдавать какую-то диагностику -- это лишь приятный бонус. Не более того. Тем более, что этого бонуса запросто может и не быть.

Вы угадали все буквы и не угадали слово.
Да, определены, именно так, как описано. Поэтому я могу выбирать между ними сам, и делать это каким-то универсальным управляемым методом.

N>>Да, другое, и я это уже пару раз подчёркивал в предыдущих сообщениях — например, в том, как вы гоняете не пристегнувшись.


S>Аналогии -- это скользкий путь и он еще быстрее ведет к недопониманиям. Тем не менее, если уж показывать примеры на аналогиях, то в моем представлении defensive programming -- это когда вы вынуждены использовать ремень безопасности всегда, и во время учебы, и во время гонок, и во время обычных поездок. А вот применение того, что вы считаете assert-ами -- это избирательное использование ремней безопасности. Мол, при обучении (в Debug) ремни пристегиваем, а на гонке (в Release) -- нет.


Ну а для кого я говорил, что используем такие, которые не выключаются при (условном) релизе?

N>>Вы ждёте "волнительных историй" вместо обсуждения по сути... Ну ждите, ждите.

S>Да уже понятно, что их не будет.

Ну я тут таки по делу, а не по литературе. Хотя вы можете что-нибудь сами рассказать.
The God is real, unless declared integer.
Re[8]: Иллюстрация
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 07.11.20 09:03
Оценка:
Здравствуйте, so5team, Вы писали:

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


S>Маленькая иллюстрация для тех, кого волнует максимальная скорость неоптимизированного кода:


Вы лучше попытайтесь ответить на заданный вопрос о влиянии "шаблонных кружев" на эффективность генерируемого кода.
Re[11]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 09:04
Оценка:
Здравствуйте, netch80, Вы писали:

NB>>а зачем?

NB>>если существующий подход нормально работает и используемые средства разработки под него заточены.

N>В том и дело, что не работает он "нормально".


нормально, это значит устраивает большинство.
иначе бы использовалась другая модель.

NB>>что именно мы получаем от придуманных нами каких-то дополнительных уровней отладки/сборки?


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

N>Вы определили те модули/функции/методы, где происходит критичное по скорости выполнение.

и начинаете оптимизировать именно эти методы/функции, переписывая их на асме, играясь с ключами компиляции и прочее.
без сомнения, ситуации, требующие индивидуального подхода, встречаются.
но мы вроде говорим об общем случае, тех самых 99% "написанных на питоне"

или я что-то не понял?
Re[12]: Иллюстрация
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 09:19
Оценка:
Здравствуйте, night beast, Вы писали:

NB>>>а зачем?

NB>>>если существующий подход нормально работает и используемые средства разработки под него заточены.
N>>В том и дело, что не работает он "нормально".
NB>нормально, это значит устраивает большинство.
NB>иначе бы использовалась другая модель.

Это не "устраивает большинство". Это 1) инерция от древних времён (70-80-е, когда эта концепция только была придумана), 2) инерция мышления тех, кто просто не представляет себе иначе и не хочет думать о других вариантах.

В IT тысячи примеров такой инерции, этот далеко не единственный. Каждый из них постепенно устраняется, но на это могут уйти десятилетия. Но размыв идёт постепенно и со стороны. Уже несколько уровней оптимизации в компиляторе — вполне источник альтернативных подходов.
В GCC, например, с 5-й версии есть прагмы задания уровня оптимизации раздельно по каждой функции. Это ещё дальше шаг в данную сторону. Ещё лет 20 и они пройдут в стандарт языка.

NB>и начинаете оптимизировать именно эти методы/функции, переписывая их на асме, играясь с ключами компиляции и прочее.

NB>без сомнения, ситуации, требующие индивидуального подхода, встречаются.
NB>но мы вроде говорим об общем случае, тех самых 99% "написанных на питоне"
NB>или я что-то не понял?

Уже топикстартер явно говорил не о стандартном случае, у него были весьма специфические хотелки. Так что, увы, не поняли.
The God is real, unless declared integer.
Re[9]: Иллюстрация
От: so5team https://stiffstream.com
Дата: 07.11.20 09:26
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

S>>Маленькая иллюстрация для тех, кого волнует максимальная скорость неоптимизированного кода:


ЕМ>Вы лучше попытайтесь ответить на заданный вопрос о влиянии "шаблонных кружев" на эффективность генерируемого кода.


Пройдите таки по ссылке и сравните эффективность кружев с -O0 и -O2.
Re[13]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 09:27
Оценка:
Здравствуйте, netch80, Вы писали:

NB>>нормально, это значит устраивает большинство.

NB>>иначе бы использовалась другая модель.

N>Это не "устраивает большинство". Это 1) инерция от древних времён (70-80-е, когда эта концепция только была придумана), 2) инерция мышления тех, кто просто не представляет себе иначе и не хочет думать о других вариантах.


возможно, но на текущий момент ситуация именно такая

N>В IT тысячи примеров такой инерции, этот далеко не единственный. Каждый из них постепенно устраняется, но на это могут уйти десятилетия. Но размыв идёт постепенно и со стороны. Уже несколько уровней оптимизации в компиляторе — вполне источник альтернативных подходов.


несколько уровней оптимизации в гсс существуют уже очень давно...

NB>>но мы вроде говорим об общем случае, тех самых 99% "написанных на питоне"

NB>>или я что-то не понял?

N>Уже топикстартер явно говорил не о стандартном случае, у него были весьма специфические хотелки. Так что, увы, не поняли.


что хочет ТС я вообще не понял.
но потом вроде обсуждение съехало в сторону
Re[13]: Возврат ошибок из недр вложенных вызовов
От: so5team https://stiffstream.com
Дата: 07.11.20 09:34
Оценка:
Здравствуйте, netch80, Вы писали:

N>Да, определены, именно так, как описано. Поэтому я могу выбирать между ними сам, и делать это каким-то универсальным управляемым методом.


Послушайте, ведь очевидно, что вы говорите про некий уникальный для вашего проекта define, который в зависимости от определения будет приводить либо к использованию operator[], либо к at. И что вы, в зависимости от каких-то факторов, определяете этот define при сборке либо так, либо иначе.

Давайте перестанем играть в эту игру и перейдем к сути.

Суть в том, что operator[] дает скорость ценой безопасности, а at обеспечивает безопасность ценой скорости. И если кому-то нужна скорость, то он выбирает именно operator[]. Причем вне зависимости от Debug/Release. А потому, что ему в итоговом коде нужна именно скорость.

Аналогично и с at.

Так что возвращаемся к тому, о чем говорилось: "Выбор между operator[] и at для vector вообще лежит вне деления на Debug/Release."

И мне не понятно, что вы этому пытаетесь возразить. Как и непонятно зачем.

N>Ну а для кого я говорил, что используем такие, которые не выключаются при (условном) релизе?


Повторюсь: если что-то не выключается при релизе, то это не assert-ы. Ну вот определение у assert-а такое. Что уж тут поделать.

N>Ну я тут таки по делу, а не по литературе. Хотя вы можете что-нибудь сами рассказать.


Так в том-то и дело, что мне не вспомнаются примеры того, чтобы скорость работы кода в Debug-е имела значение.
Тогда как у вас, можно предположить, подобные примеры имеются:

Во-первых, как уже сказано, и в отладочном режиме скорость может быть важна, и критически важна.

Вот мне было бы интересно (без сарказма) узнать про примеры того, как и почему в Debug-е скорость кода важна, да еще и критически важна.
Re[10]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 07.11.20 09:39
Оценка:
Здравствуйте, so5team, Вы писали:

S>Евгений, видимо, существует в очень комфортных условиях. Скажем, у него время отклика 10ms и его код (причем, скорее всего, только его, без каких-либо внешних зависимостей) даже в Debug сборке успевает в это время уложиться.


Евгений существует в сильно различных условиях. Когда есть возможность, он предпочитает отлаживать свои ядерные драйверы в виртуалках, чтобы не подключать отдельный отладочный ноутбук, обмен которого с отладчиком, даже по гигабитному сетевому шнурку, гораздо медленнее, чем у виртуалки через VirtualKD. Если код в отладочных сборках будет вообще без оптимизаций, то тормоза в самых внутренних циклах, вместе с тормозами VMM и его эмулятора HD Audio, не позволят поддерживать стабильный звуковой поток с периодом меньше 10 мс. А так оно вполне себе работает и на периодах 3-5 мс, а в особо удачных вариантах — и 1 мс. Это, напомню, в виртуалках. А непосредственно на железе, даже 15-летней давности, мне вообще по барабану, отладочная сборка или релизная — обе с большим запасом укладываются в 500 мкс, а уменьшить период уже не позволяет разрешение системного таймера.

S>что он будет делать, если у него оптимизированный код будет с трудом в 10ms укладываться.


Будет оптимизировать алгоритм, вестимо.

S>Он все еще продолжит рассуждать о важности скорости в Debug варианте?


Он в первую очередь рассуждает об относительных накладных расходах, затрачиваемых на организацию удобств. Когда они разумны (от единиц процентов на мелкие удобства, до 10-20 на серьезные), это оправдано. Многократное копирование содержимого объекта при возвратах из функций — это сотни-тысячи процентов накладных расходов. В масштабе всего приложения это, конечно, мелочи, но здесь ярко проявляется способность C++ к малозаметному созданию совершенно неадекватных тормозов. А активное и невнимательное использование шаблонов в традиционном для C++ стиле "ну ужасно, ну криво, но работает же!" это и провоцирует, и маскирует.

Если отладочная сборка тормозит (хотя бы по отдельным фрагментам кода) по сравнению с релизной разумно (в 2-3 раза), то оснований для беспокойства нет. Если же она вдруг начинает тормозить в десятки-сотни раз — это безусловно повод для беспокойства.

S>на том же MSVC в Debug и Release вы вынуждены линковаться к разным версиям runtime-библиотек.


Почему вдруг "вынуждены"? Можете линковаться к любой на выбор.
Re[12]: Иллюстрация
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 07.11.20 09:47
Оценка:
Здравствуйте, night beast, Вы писали:

NB>нормально, это значит устраивает большинство.


Если в смысле "пипл хавает", то да.

NB>и начинаете оптимизировать именно эти методы/функции, переписывая их на асме, играясь с ключами компиляции и прочее.


Правильнее все-таки сперва пытаться оптимизировать алгоритм, затем играться с режимами компиляции, и лишь после этого — переписывать на асме.
Re[13]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 09:53
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

NB>>нормально, это значит устраивает большинство.


ЕМ>Если в смысле "пипл хавает", то да.


ну тебя же не напрягает использование большинством библиотеки std?
ведь можно для конкретных кейсов и лучше написать.
Re[10]: Иллюстрация
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 07.11.20 10:12
Оценка:
Здравствуйте, so5team, Вы писали:

S>Пройдите таки по ссылке и сравните эффективность кружев с -O0 и -O2.


Она как-то изменится, если "шаблонные кружева" убрать совсем? Напомню, речь шла о возврате объекта по значению из набора вложенных вызовов функций, а MSVC++ умеет избегать многократных копирований только при включенной оптимизации.

Вы утверждали
Автор: so5team
Дата: 05.11.20
, будто нелегко одним взглядом определить, во что будут транслироваться "современные шаблонные кружева". Я в ответ спросил, каким образом "кружева" могут влиять на кодогенерацию. Если компилятор не умеет что-то оптимизировать, то никакие шаблоны не спасут. А если умеет, то сможет и на любом уровне шаблонных наворотов. Поэтому нет никакого повода для иронии.
Re[14]: Иллюстрация
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 07.11.20 10:26
Оценка:
Здравствуйте, night beast, Вы писали:

NB>ну тебя же не напрягает использование большинством библиотеки std?


Я их вообще не использую.

Когда я в середине 90-х начинал писать на C++, они были в зачаточном состоянии, впоследствии же концепции и реализации неоднократно менялись. Вместо того, чтобы регулярно участвовать в обсуждениях "какого хрена std::xxx глючит на yyy", я предпочел сразу сделать себе набор простых классов и шаблонов для повседневных нужд, и полностью устраниться от этого класса проблем. Мне по уши хватало собственных глюков компиляторов, особенностей оптимизации в разных версиях, различий в SDK/DDK/WDK и т.п.

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

Но все это, само собой, возможно лишь при разработке замкнутых, технологически несложных продуктов (драйверы, системные расширения, утилиты и т.п.). Если б я взялся за масштабные проекты, требующие вдобавок интеграции с существующим софтом — само собой, пришлось бы использовать типовые библиотеки — и шаблонные, и интерфейсные.
Re[11]: Иллюстрация
От: so5team https://stiffstream.com
Дата: 07.11.20 10:27
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

S>>Пройдите таки по ссылке и сравните эффективность кружев с -O0 и -O2.


ЕМ>Она как-то изменится, если "шаблонные кружева" убрать совсем?


Если вас интересует именно этот вопрос, то поищите ответ сами: код на godbolt-е есть, можете изменять его как вздумается.

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

ЕМ>Вы утверждали
Автор: so5team
Дата: 05.11.20
, будто нелегко одним взглядом определить, во что будут транслироваться "современные шаблонные кружева".


Так и есть.

EM>Я в ответ спросил, каким образом "кружева" могут влиять на кодогенерацию.


Пример на godbolt-е. Может возникнуть изрядный оверхэд при отключенной оптимизации.

EM>Если компилятор не умеет что-то оптимизировать, то никакие шаблоны не спасут.


Еще раз: компилятор умеет и умеет подобное уже лет 25. Вопрос в том, зачем кому-то от этого отказываться. А сарказм возникает из-за того, что вы мало того, что заведомо отказываетесь, так еще и считаете это нормой.
Re[15]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 10:31
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

NB>>ну тебя же не напрягает использование большинством библиотеки std?


ЕМ>Я их вообще не использую.


возможно.
но не выходишь же с плакатом "долой STL"?
в чем принципиальная разница того "пипл хавает" и обсуждаемого здесь разделения на дебаг/релиз?
Re[12]: Иллюстрация
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 07.11.20 11:07
Оценка:
Здравствуйте, so5team, Вы писали:

ЕМ>>Она как-то изменится, если "шаблонные кружева" убрать совсем?


S>код на godbolt-е есть, можете изменять его как вздумается.


Какой смысл этим заниматься, если логика работы оптимизатора не зависит от того, шаблонный код он обрабатывает, или нешаблонный? Если известно, например, что компилятор не умеет оптимизировать какие-то операции с 64-разрядными значениями для 32-разрядных архитектур, то этого не добиться, завернув исходную конструкцию хоть в сотню хитровложенных шаблонов.

Так и здесь: достаточно увидеть в этих "современных шаблонных кружевах" возврат объекта по значению, чтобы с уверенностью утверждать, что результирующий код, побитно копирующий объект перед возвратом из каждой функции, никуда не денется при любой сложности "кружев".

S>Приведенный же пример показывает, какой оверхэд вы получите от полезных для надежности кода шаблонов, если избегаете включения оптимизатора в компиляторе.


В конкретно этом случае использование стандартной реализации expected не приведет к сколько-нибудь заметному росту надежности моего кода, а вот геморроя добавит гарантированно, поэтому я с сходу и отмел этот вариант.

S>Соответственно, меня лично интересует то, зачем какие-то одаренные личности отказываются от оптимизатора по доброй воле.


Одаренные личности Вам уже и так, и этак разжевали, что использование оптимизатора во многих случаях лишает возможности увидеть значения всех переменных и вести пошаговую отладку, если вдруг сработает какая-то из охранных проверок. То, что это трудно или невозможно в полностью релизных конфигурациях, ни исключает желания иметь такую возможность в отладочных.

S>Пример на godbolt-е. Может возникнуть изрядный оверхэд при отключенной оптимизации.


А при включенной — потеряется возможность адекватно отлаживать код. Если достигаемое удобство значимо перевешивает этот недостаток — его можно принять. В данном же случае удобство весьма условно.

EM>>Если компилятор не умеет что-то оптимизировать, то никакие шаблоны не спасут.


S>Еще раз: компилятор умеет и умеет подобное уже лет 25.


Хорошо, уточняю: "не умеет оптимизировать без потери других важных свойств кода".
Re[13]: Иллюстрация
От: so5team https://stiffstream.com
Дата: 07.11.20 11:22
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Какой смысл этим заниматься, если логика работы оптимизатора не зависит от того, шаблонный код он обрабатывает, или нешаблонный?


Смысл в том, что нешаблонные варианты tagged_scalar под каждое сочетание scalar_type+tag писать вряд ли будут. Будут использовать в коде голые скалярные типы. А от tagged_scalar будут оказываться потому, что в неоптимизированных вариантах есть оверхэд.

ЕМ>Так и здесь: достаточно увидеть в этих "современных шаблонных кружевах" возврат объекта по значению, чтобы с уверенностью утверждать, что результирующий код, побитно копирующий объект перед возвратом из каждой функции, никуда не денется при любой сложности "кружев".


Тут нужно определиться с тем, что вы понимаете под объектом. std::pair<int, int> -- это объект, и expected<int, int> -- тоже объект, и expected<int, std::string> -- объект, и expected<int, unique_ptr<error>> -- объект. Только стоимость возрата этих объектов будет разная. Включая и отсутствие побитного копирования в некоторых случаях.

ЕМ>Одаренные личности Вам уже и так, и этак разжевали, что использование оптимизатора во многих случаях лишает возможности увидеть значения всех переменных и вести пошаговую отладку, если вдруг сработает какая-то из охранных проверок. То, что это трудно или невозможно в полностью релизных конфигурациях, ни исключает желания иметь такую возможность в отладочных.


Если вам скорость неоптимизированного кода нужна только для отладки и вам повезло работать в условиях, когда просадка производительности в 2-3 раза из-за выключенной оптимизации погоды для вас не делает вообще, то вопросов больше нет.
Re[16]: Иллюстрация
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 07.11.20 11:41
Оценка:
Здравствуйте, night beast, Вы писали:

NB>в чем принципиальная разница того "пипл хавает" и обсуждаемого здесь разделения на дебаг/релиз?


Суть в том, что, сорвав одну виноградину в большом винограднике, Вы не создадите в нем заметных изменений. А если придет сто тысяч человек, и каждый сорвет по виноградине, винограда может не остаться.

Так и библиотеками: большинство совершенно не задумывается о том, что там внутри, какой ценой даются те или иные преимущества — они просто составляют нужные конструкции согласно документации. После этого нередко получается [исходный] код, о котором даже опытные программисты могут сказать, что он "оптимален", и единственная возможность его ускорения — это применение оптимизаций кодогенератора. Поэтому подавляющее большинство, от имени которого выступает so5team, рассматривает неоптимизированные сборки типа "Debug", как "плохие", "неполноценные", "негодные", а оптимизированные типа "Release" — как "нормальные", "правильные", "рабочие". А должно быть иначе: обычная, неоптимизированная сборка — "нормальная", "рабочая", "годная", а оптимизированная — "улучшенная", "продвинутая", "предельная" и т.п.
Re[14]: Возврат ошибок из недр вложенных вызовов
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 11:52
Оценка:
Здравствуйте, so5team, Вы писали:

S>Послушайте, ведь очевидно, что вы говорите про некий уникальный для вашего проекта define, который в зависимости от определения будет приводить либо к использованию operator[], либо к at. И что вы, в зависимости от каких-то факторов, определяете этот define при сборке либо так, либо иначе.


Да. Как и множество других.

S>Давайте перестанем играть в эту игру и перейдем к сути.


Это и есть суть.

S>Так что возвращаемся к тому, о чем говорилось: "Выбор между operator[] и at для vector вообще лежит вне деления на Debug/Release."

S>И мне не понятно, что вы этому пытаетесь возразить. Как и непонятно зачем.

Верно. Оно лежит вне деления на Debug/Release, в прокрустовом ложе которого вы пытаетесь лежать.
Оно является всего лишь одним из параметров, которые можно регулировать при компиляции кода.

N>>Ну а для кого я говорил, что используем такие, которые не выключаются при (условном) релизе?

S>Повторюсь: если что-то не выключается при релизе, то это не assert-ы. Ну вот определение у assert-а такое. Что уж тут поделать.

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

N>>Ну я тут таки по делу, а не по литературе. Хотя вы можете что-нибудь сами рассказать.


S>Так в том-то и дело, что мне не вспомнаются примеры того, чтобы скорость работы кода в Debug-е имела значение.

S>Тогда как у вас, можно предположить, подобные примеры имеются:

Я уже приводил. В качестве примера попроще — возьмите установку, которой надо отдавать команды вовремя, иначе что-то не куда надо уедет.
The God is real, unless declared integer.
Re[14]: Иллюстрация
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 11:54
Оценка:
Здравствуйте, night beast, Вы писали:

NB>>>нормально, это значит устраивает большинство.

NB>>>иначе бы использовалась другая модель.

N>>Это не "устраивает большинство". Это 1) инерция от древних времён (70-80-е, когда эта концепция только была придумана), 2) инерция мышления тех, кто просто не представляет себе иначе и не хочет думать о других вариантах.


NB>возможно, но на текущий момент ситуация именно такая


Где? В Visual Studio? Ну я с ней не работаю и не планирую, а мои средства имеют сильно бо́льший спектр вариантов.

N>>В IT тысячи примеров такой инерции, этот далеко не единственный. Каждый из них постепенно устраняется, но на это могут уйти десятилетия. Но размыв идёт постепенно и со стороны. Уже несколько уровней оптимизации в компиляторе — вполне источник альтернативных подходов.

NB>несколько уровней оптимизации в гсс существуют уже очень давно...

Да. Но влиять на эти концепции они начали достаточно недавно, примерно с началом массовой миграции хомячков на Linux.
The God is real, unless declared integer.
Re[14]: Иллюстрация
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 07.11.20 11:58
Оценка:
Здравствуйте, so5team, Вы писали:

S>стоимость возрата этих объектов будет разная. Включая и отсутствие побитного копирования в некоторых случаях.


Если Вы знаете случаи, в которых MSVC++ делает возврат по значению любых объектов без копирования, когда отключена оптимизация — поделитесь, пожалуйста, буду благодарен. Я таких случаев не нашел. Единственное исключение — это RVO, когда объект конструируется непосредственно в операторе return. Но для того, чтобы сконструировать объекта в return, необходимо инициализировать все значимые члены. ABI не позволяет в таком случае вернуть адрес объекта — только содержимое.

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

S>Если вам скорость неоптимизированного кода нужна только для отладки и вам повезло работать в условиях, когда просадка производительности в 2-3 раза из-за выключенной оптимизации погоды для вас не делает вообще, то вопросов больше нет.


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

Поэтому в общем случае оптимизацию генерируемого кода следует рассматривать, как метод повышения производительности, но не как необходимое условие работоспособности программы.
Re[17]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 11:58
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Так и библиотеками: большинство совершенно не задумывается о том, что там внутри, какой ценой даются те или иные преимущества — они просто составляют нужные конструкции согласно документации. После этого нередко получается [исходный] код, о котором даже опытные программисты могут сказать, что он "оптимален", и единственная возможность его ускорения — это применение оптимизаций кодогенератора. Поэтому подавляющее большинство, от имени которого выступает so5team, рассматривает неоптимизированные сборки типа "Debug", как "плохие", "неполноценные", "негодные", а оптимизированные типа "Release" — как "нормальные", "правильные", "рабочие". А должно быть иначе: обычная, неоптимизированная сборка — "нормальная", "рабочая", "годная", а оптимизированная — "улучшенная", "продвинутая", "предельная" и т.п.


поправлю немного
Debug -- версия, максимально пригодная для отладки. в которой основной упор сделан на обнаружение ошибок.
Release -- версия, которая отдается клиенту. в которой упор сделан на производительность. но это не исключает использования в этой сборке отладочных символов.

нет никаких "правильная"/"неправильная". есть просто разное назначение.
и в сборке Debug критерий производительности играет не очень важную роль.

ну, по крайней мере я так воспринимаю различие в сборках.
Re[15]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 12:14
Оценка:
Здравствуйте, netch80, Вы писали:

NB>>возможно, но на текущий момент ситуация именно такая


N>Где? В Visual Studio? Ну я с ней не работаю и не планирую, а мои средства имеют сильно бо́льший спектр вариантов.


не только
https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html
Re[15]: Иллюстрация
От: so5team https://stiffstream.com
Дата: 07.11.20 12:14
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Если Вы знаете случаи, в которых MSVC++ делает возврат по значению любых объектов без копирования, когда отключена оптимизация — поделитесь, пожалуйста, буду благодарен.


Так уж получилось, что меня не интересуют показатели производительности кода, который собирается с выключенной оптимизацией. Для чего такой код может понадобиться понять можно. Вот что сложно понять, так это кому и зачем нужна производительность в этом случае. Ну вот вам нужно, ну и ОК, чего только в жизни не бывает.

ЕМ>Наоборот — это Вам не повезло оказаться в условиях, когда только автоматическая оптимизация кодогенерации позволяет решить поставленную задачу.


Не нужно подменять понятия. Автоматическая оптимизация позволяет забесплатно избавиться от бойлерплейта, который возникает по различным причинам (обеспечение надежности, безопасности, гибкости, настраиваемости и т.д.).

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


Я не делал знака равенства между "производительностью" и "работоспособностью". Более того, это что-то странное. Работоспособность должна быть априори, производительность -- это всего лишь одно из качеств работоспособного кода.

Оптимизация здесь при том (повторяюсь), что позволяет избавится от накладных расходов, связанных с обеспечением работоспособности кода (см. пример с tagged_scalar). Без оптимизации пришлось бы отказываться от ряда приемов программирования, потому что компилятор тогда бы привносил в код оверхэд и это сказывалось бы на производительность. И в таких условиях достижение работоспособности оказывалось бы дороже.
Re[16]: Иллюстрация
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 13:03
Оценка:
Здравствуйте, night beast, Вы писали:

NB>>>возможно, но на текущий момент ситуация именно такая


N>>Где? В Visual Studio? Ну я с ней не работаю и не планирую, а мои средства имеют сильно бо́льший спектр вариантов.


NB>не только

NB>https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html

Ну так
1) это только образцы — возможно больше.
2) там с ходу больше список вариантов — вы сами-то ссылку прочли?
The God is real, unless declared integer.
Re[18]: Иллюстрация
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.11.20 13:11
Оценка:
Здравствуйте, night beast, Вы писали:

NB>нет никаких "правильная"/"неправильная". есть просто разное назначение.

NB>и в сборке Debug критерий производительности играет не очень важную роль.

Ну вот у вас "не очень важную".
А so5team@ заглючило на том, что якобы вообще тут производительность не имеет значения, и не разглючивает.
The God is real, unless declared integer.
Re[17]: Иллюстрация
От: night beast СССР  
Дата: 07.11.20 13:11
Оценка:
Здравствуйте, netch80, Вы писали:

NB>>не только

NB>>https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html

N>Ну так

N>1) это только образцы — возможно больше.

да. и эти образцы используют разные библиотеки
поиск по слову _DEBUG выдал ~50 файлов из ~150 Find*

N>2) там с ходу больше список вариантов — вы сами-то ссылку прочли?


естественно
дебаг и несколько вариантов релиза
Re[3]: Guaranteed Copy Elision в C++17
От: Alexander G Украина  
Дата: 08.11.20 20:23
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:


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


В контексте этой темы, Guaranteed Copy Elision в C++17.

Это как бы обязательный RVO, и это фича компилятора, не библиотек
Русский военный корабль идёт ко дну!
Отредактировано 08.11.2020 20:25 Alexander G . Предыдущая версия .
Re[4]: Guaranteed Copy Elision в C++17
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 08.11.20 20:44
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>В контексте этой темы, Guaranteed Copy Elision в C++17.

AG>Это как бы обязательный RVO, и это фича компилятора, не библиотек

Безусловная (без включения режимов оптимизации кода) RVO поддерживается в MSVC++ еще с компилятора 15.00 (VS 2008). А вот безусловная NRVO не поддерживается даже в 19.21 (VS 2019).
Re[5]: Возврат ошибок из недр вложенных вызовов
От: ononim  
Дата: 09.11.20 08:50
Оценка:
ЕМ>При помощи множества последовательных вызовов приходится искать, например, поддерживаемые звуковые форматы — в интерфейсах не предусмотрено способа получения исчерпывающего списка хоть конкретных форматов, хоть их диапазонов. Сама система тоже делает множественные вызовы. Если устройство возвращает ошибку "не подходит" то пробуем следующую комбинацию.
ЕМ>А если вдруг возвращает "устройство отключено", "отказ в доступе" и т.п., то это уже нештатная ситуация, о которой нужно сообщить именно на самый верх.
Ну, сделай два типа исключений — один для retry-able, второй — для fatal проблем.
Можно вообще на каждую проблему свое исключение, отнаследованное от тех же групп retry-able/fatal
Как много веселых ребят, и все делают велосипед...
Re[6]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 09.11.20 13:29
Оценка:
Здравствуйте, ononim, Вы писали:

O>Ну, сделай два типа исключений — один для retry-able, второй — для fatal проблем.


Для повторяемых операций исключения допустимы лишь в случае, когда что-то пошло совсем непредсказуемо, и верхний уровень (человек или код) решает повторить попытку в надежде на скорейший успех. В ситуации, когда перспектива многократных повторов заранее известна, исключения — моветон. Хотя нынче многие строят алгоритм именно так, используя исключения просто для информирования о состоянии.
Re[7]: Возврат ошибок из недр вложенных вызовов
От: ononim  
Дата: 09.11.20 23:28
Оценка:
O>>Ну, сделай два типа исключений — один для retry-able, второй — для fatal проблем.
ЕМ>Для повторяемых операций исключения допустимы лишь в случае, когда что-то пошло совсем непредсказуемо, и верхний уровень (человек или код) решает повторить попытку в надежде на скорейший успех. В ситуации, когда перспектива многократных повторов заранее известна, исключения — моветон. Хотя нынче многие строят алгоритм именно так, используя исключения просто для информирования о состоянии.
В конечном итоге это все вкусовщина. Активное использование исключений в целом налагает определенные требование на код, а значит предполагает адекватный уровень команды, что не всегда достижимо, если не вы эту команду контролируете. Но имхо делить ситуацию на "ужас-ужас-ужас" "ужас" и "норм" и использовать разные механизмы для разных уровней ужаса — это лишь повышает сложность, а профит не очень заметен. Разве что, если надо чтоб "ужас" быстро отрабатывал.
Как много веселых ребят, и все делают велосипед...
Re[8]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 10.11.20 20:10
Оценка:
Здравствуйте, ononim, Вы писали:

O>Активное использование исключений в целом налагает определенные требование на код


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

O>имхо делить ситуацию на "ужас-ужас-ужас" "ужас" и "норм" и использовать разные механизмы для разных уровней ужаса — это лишь повышает сложность, а профит не очень заметен. Разве что, если надо чтоб "ужас" быстро отрабатывал.


"Быстро" — это насколько? Любое исключение C++ обрабатывается через исключение ОС (по крайней мере, под виндой). Если каждая функция, которая может отработать с различными особенностями, для информирования о них будет бросать исключения — накладные расходы возрастут весьма заметно. Конечно, если таких функций немного, то на общем фоне они могут и потеряться, но сам подход к такому использованию исключений ущербен, поскольку к нему легко привыкнуть, а когда вдруг окажется, что расходы стали чрезмерными, затраты на переделку, скорее всего, окажутся неприемлемыми. И начнется традиционное "купите процессор побыстрее".
Re: Возврат ошибок из недр вложенных вызовов
От: gwg-605 Россия  
Дата: 08.03.21 22:51
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Типичная ситуация: функция верхнего уровня вызывает функцию более низкого уровня, та — следующую и т.п., и где-то на N-м уровне очередной вызов возвращает ошибку. Если это что-то уникальное, то можно вернуть наверх (хоть через обычные return, хоть через исключения) уникальный код и/или описание. Но если ошибка общего характера (нехватка ресурсов, отказ в доступе, разрыв соединения и т.п.), то неплохо бы вернуть наверх более подробную информацию, которую можно показать пользователю, чтобы он имел более-менее адекватное представление о проблеме.


Надо понимать, что есть три класса ошибок:
1. Ошибки которые может исправить только пользователь, типа неправильны путь к файлу, неправильное значение параметра и тп
2. Ожидаемые кодом ошибки которые могут корректно обрабатываться самим кодом, полное разнообразие
3. Приложение умерло, типа нет памяти


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

Думаю это вопрос из серии "священные войны"

Я пришел к некоторому объекту: CError который используется для ошибок из пунктов №1 и №2. Это класс враппер над референсным контейнером для ошибки. Если ошибки нет, то передается просто nullptr, иначе указатель на контейнер с даннмыи об ошибке. Ошибки имеют уникальный идентификатор — для обработки внутри кода, и есть опциональное текстовое поле описывающее ошибку для пользователя. Также ошибка может содержать вложенные ошибки и доп данные (пара ключ-данные).

Функция которая создает ошибку решает присвоить только номер ошибки:
err.Set( ErrorBufferNotEnough )

или сформировать читабельное сообщение об ошибке:
err.Set( FileNotFound, "File '%s' not found", file_name )


На верхнем уровне функция может просто пределать ошибку выше:
err = f();
if( err.IsError() ) {
  return err;
}

или сформировать новую:
err = f();
if( err.IsError() ) {
  return CError( ErrorFatal );
}

или сформировать стек ошибок:
err = f();
if( err.IsError() ) {
  return CError( ErrorFatal, err );
}

или передавать ошибки со сформированнымим сообщениями, а другие хендлить другим образом:
err = f();
if( err.HasMsg() ) {
  return err;
} else if( err.IsError() ) {
  return CError( ErrorFatal, err );
}


Всегда можно получить ошибку err.GetMessage( opt = 0 ), по умолчанию получаешь сообщени об ошибке самого верхнего уровня, но в зависимости от опций можно получить весь стек ошибок. Если было сформировано сообщение, то получим это сообщение, если нет то стандартное сообщение ассоциированное с номером ошибки.

Так же можно аттачить доп данные (ключ-данные) к ошибке:
CError result;
if( check username field ) {
   CError err( ErrorInvalidConfig, "Invalid value '%s'", val );
   err[ "field" ] = "username";
   result += err;
}
if( check first_name field ) {
   CError err( ErrorInvalidConfig, "Invalid value '%s'", val );
   err[ "field" ] = "first_name";
   result += err;
}
return result;

GetMessage() вернет:
username: Invalid value 'zzzz'
first_name: Invalid value 'ddddd'


Сами ошибки можно передавать разными способами:
возвращаемое значение:
CError = f1();

как output значение:
CError err;
auto r = f1( err );

через TLS:
auto r = f1();
if( r == InvalidValue ) {
   CError err = CError::GetLastError();
}


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

Для ошибок из третьего пункта бросаю исключение. в 99% случаев это бэд аллок.

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

G6>Я пришел к некоторому объекту: CError который используется для ошибок из пунктов №1 и №2. Это класс враппер над референсным контейнером для ошибки. Если ошибки нет, то передается просто nullptr, иначе указатель на контейнер с даннмыи об ошибке.


Я примерно к тому же пришел за время существования темы. Только пока у меня везде прокидывается изнутри наружу простенький контейнер, содержащий код ошибки и указатель на ее расширенное описание. Возвращать указатель, наверное, будет и изящнее, и экономичнее, но мне не хотелось бы закладываться на плюсовые исключения, которые до сих пор толком не поддерживаются в ядре. Впрочем, на случай нехватки памяти можно предусмотреть статический объект, или даже какой-то их запас, если захочется конкретизировать ситуацию.
Re[8]: tagged_scalar
От: sergii.p  
Дата: 12.03.21 06:59
Оценка:
Здравствуйте, so5team, Вы писали:

S>Шаблон tagged_scalar там сделан для того, чтобы при вызове конструктора limiter нельзя было перепутать аргументы, которые имеют один и тот же тип. Такой вот незамысловатый трюк для того, чтобы уменьшить количество ошибок в коде (ну нельзя же все на откуп assert-ам отдавать, ей Богу).


попутно замечу, что подобный tagged_scalar для типов unsigned int легче можно реализовать с помощью enum. Не надо дополнительно реализовывать операции сравнения, вычисление хэша и т. п. std::byte реализован именно так. Так что можно сказать, канонический подход.
https://godbolt.org/z/vbx1qK
Re[2]: Возврат ошибок из недр вложенных вызовов
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 14.03.21 09:12
Оценка:
Здравствуйте, gwg-605, Вы писали:

G6>Я пришел к некоторому объекту: CError


Забыл уточнить: в Вашей практике бывала надобность в счетчике ссылок для таких объектов? Или они всегда безусловно уничтожались после анализа содержимого?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.