Если для того, что бы просто писать на языке, надо обязательно знать во что оно именно компилируется в асме, держдать в голове кучу табличек с исключениями и особенностями реализации конретного компилятора
Назвать правило 5 тонкостями не могу при всем уважении. Это база, которую нужно знать, чтобы нормально писать на современном C++.
Тонкостью для того же правила 5 можно было бы назвать наличие noexcept на операторах/конструкторах копирования/перемещения (или отсутствия этого самого noexcept). ИМХО.
Если хочется тонкостей, то на сайте PVS-Studio сейчас публикуется серия статей про UB в Си и C++. Вот там тонкостей разной степени тонкости в ассортименте.
Вот в обобщенном коде, где тип заранее неизвестен, это может быть действительно большая разница, а тут-то?
Если взять за правило ставить {} для вызова дефолтного конструктора, то не будет разницы пишешь ты обобщенный код или конкретный. Особенно если конкретный со временем трансформируется в обобщенный или наоборот.
Комментарий ревьюера: «Ты давай так не делай. Ты лучше просто точку с запятой оставь, а фигурные скобки убери отсюда».
Странная претензия.
Если у нас есть класс, а не built-in тип и я хочу позвать дефолтный конструктор, то не надо использовать пустые фигурные скобки. Но, с другой стороны, если у меня built-in тип и я хочу, чтобы integer инициализировался нулем, то почему бы не использовать фигурные скобки, которые пойдут в value initialization, а value initialization приведет к zero initialization.
Никто в здравом уме в продуктовом коде не будет использовать new, buf[], union и прочий С++89.
Как ни странно, но для union-а до сих пор есть место в продуктовом коде. Поскольку union применяют для экономии места и когда есть возможность определить тип содержимого union-а внешними средствами (или через общий префикс для содержащихся в union-е структур), то union-ом можно сэкономить, по меньшей мере, байт на каждый экземпляр union-а. А когда таких экземпляров пара-тройка миллионов, то и экономия получается немаленькая. Особенно с учетом эффекта выравнивания данных.
А почему вы для C# выбираете какие-то тривиальные примеры?
Кто вам сказал, что работа с JSON и БД -- это тривиально? Если это в вашей реальности так, то это вовсе не означает, что это мной подразумевалось. Т.е. речь о ваших домыслах.
"легко представить, что на С# вы используете Unity, а на С++ Unreal"
Не написал поскольку не имел дел ни с тем, ни с другим.
Вам просто не надо занимать позицию интеллектуального превосходства заявляя, что на С++ задачи огого, а в шарпе люди только json из базы перекладывают.
А теперь покажите пальцем, где бы я говорил и про "на C++ задачи огого", и, особенно, про "интеллектуального превосходства".
Что-то вы себе выдумали, а потом в этом обвинили собеседника.
Речь как раз и шла о том, что решая разные задачи на разных языках вам нужны разные возможности. Поэтому ничего удивительного в том, что в C# вам не нужны фичи C++.
Зачем из таких очевидных вещей устраивать цирк с "интеллектуальным превосходством" -- хз.
Вы бы взяли труд подумать о том, о чем именно вас спросили.
Легко представить, что на C# вы берете JSON-ы и перегоняете их в БД, или в обратном порядке.
Тогда как на C++ вы занимаетесь анализом видеопотоков или deep packet inspection.
И это практически непересекающиеся области. Т.е. в C++ вам нафиг не нужно иметь LINQ, тогда как в C# вам не нужны C++ные шаблоны со специализацией под узкие конкретные случаи. Откуда и проистекает "Я пишу на С++ и шарпе и еще ни разу в шарпе мне не потребовалась функциональность из С++".
Но если вы и на C++, и на C# занимаетесь одинаковыми задачами, то было бы интересно послушать что же это за задачи такие.
Что касается моноброви, то, как по мне, то это лучше, чем изначальное использование одинарной "крышки". Т.е. планировалось ^Type, сейчас хотя бы ^^Type, что и заметно лучше, и не вызывает диссонанса с уже имеющимся в C++ operator^.
Что касается [: :], то вроде бы это распространенная тема в различных template engines, когда есть специальные маркеры, отличающие текст самого шаблона, от места подстановки генерируемого текста. И это удобно. Код вида:
[: template_arguments_of(type_of(^^name))[1] :]
хоть и неважно читается из-за плохого выбора набора символов, но все-таки гораздо лучше условного:
Да что угодно, если уже все это заключается в квадратные скобки: [~ ~], [@ @], [# #], [* *]. Можно было бы, наверное, и ^ задействовать, типа [^ ^], раз уж "крышечка" просочилась в рефлексию, и оно бы было бы даже логичнее, но тогда, боюсь, кто-то напишет [^^^something^].
Лично я бы выбирал между: [@ template_arguments_of(type_of(^^name))[1] @] [# template_arguments_of(type_of(^^name))[1] #] но мои вкусы несколько специфичны ;)
Когда стандартизаторы пытаются подсчитать биты (bit) в байте (byte), но при этом именуя его количество как CHAR_BIT (char-bit), то только у меня одного возникает когнитивный диссонанс?
Возможно, у вас и у тех, кто пришли в C++ минуя чистый Си.
Интересно, а в комитете всех устраивает использование оператора "баян", т.е. [: :] в рефлексии? ИМХО, так это чуть ли не максимально нечитаемая комбинация из тех, что можно было придумать. Двоеточия на фоне квадратных скобочек не считываются :(
Упоротый сторонник исключений может глянуть код Qt. Много кода, много-много кода.
Ага, отличный пример того, как десятилетиями прятать голову в песок под мантры "bad_alloc-а не бывает, после bad_alloc-а жизни нет".
А можно ли в Qt-шном коде безопасно вызывать std::vector::at или std::optional::value?
Пока с наглядными примерами надежного кода без исключений у вас не получается. Еще попробуете?
А в ваших исключишках забивают абсолютно все.
Зря вы прибегаете к аргументам "зато у вас негров линчуют", клоуном от этого вы быть не перестаете, скорее наоборот.
предназначены для аварийного завершения программы в случае так называемых НЕИСПРАВИМЫХ ошибок. Да, есть defer (как и goto там есть), но идея в том
что если факты противоречат гипотезам, то тем хуже для фактов. В Go паники спокойно перехватываются, а как раз defer-ы позволяют чистить ресурсы для того, чтобы продолжить после восстановления без утечки чего-либо.
Надёжный код прекрасно пишется без исключений.
"прекрасно" -- это сильно (очень сильно) преувеличено. Но вот то, что это очень дорого и очень многословно -- это да.
И тьма примеров тому.
Пока от вас не увидел ни одного.
Вот как вы пишете надёжный код с исключениями, тут совсем не понятно
А мне как раз понятно почему вам непонятно.
надёжность будет зависеть от того, кто будет использовать ваш код
Надежность моего кода зависит от того, как я его написал. При этом я не несу ответственности за то, что кто-то как-то написал с использованием моего кода. Так что этот звидежь отправляем в /dev/null.
если вы не робот, вы обязательно упустите исключение в какой-то функции
А мне и не нужно ловить все исключения из каждой функции. Вот чего не понимаю упоротые противники исключений, так это того, что исключения ловятся гораздо реже, чем бросаются.
при использовании либ, собранных разными компиляторами вся ваша "надёжность" на ваших исключишках идёт строем в одно место.
Это какая-то страшилка из 1990-х. В современном мире, когда проекты собирается из open-source компонентов, такой проблемы не существует как класса. Более того, очень много C++ных проектов вообще затачивается по один единственный компилятор.
Или я прям должен по требованию анонима сбросить код коммерческих либ?
Ирония в том, что анонимом в данном разговоре являетесь вы.
Может быть, но мне интересно посмотреть на то, как пишут код настолько упоротые противники исключений.
Посмотрите любой код на всяких си
Время от времени приходится. Там либо забивают на часть возможных проблем (например, часто не контролируются результаты strdup или sprintf). Либо же сразу вызывают abort и все.
голанг
Там сплошное if err != nil из-за которых прикладная логика теряется под толщей подобных if-ов и, плюс к тому, в Go есть паники.
Не очень понятно, как кривые плюсовые исключения в вашем сознании положительно влияют на надёжность.
То, что вам не понятно -- это очевидно. Но вопрос не в этом, а в том, как писать надежный код без исключений на C++ (не Rust, не Go, а именно на C++). И примеров, как я понимаю, от вас не будет.
Успокойтесь, это не обязательно.
Назвать правило 5 тонкостями не могу при всем уважении. Это база, которую нужно знать, чтобы нормально писать на современном C++.
Тонкостью для того же правила 5 можно было бы назвать наличие noexcept на операторах/конструкторах копирования/перемещения (или отсутствия этого самого noexcept). ИМХО.
Если хочется тонкостей, то на сайте PVS-Studio сейчас публикуется серия статей про UB в Си и C++. Вот там тонкостей разной степени тонкости в ассортименте.
Если взять за правило ставить {} для вызова дефолтного конструктора, то не будет разницы пишешь ты обобщенный код или конкретный. Особенно если конкретный со временем трансформируется в обобщенный или наоборот.
При беглом просмотре статьи вообще никаких тонкостей не обнаружилось.
Странная претензия.
И выводы не менее странные.
Как ни странно, но для union-а до сих пор есть место в продуктовом коде. Поскольку union применяют для экономии места и когда есть возможность определить тип содержимого union-а внешними средствами (или через общий префикс для содержащихся в union-е структур), то union-ом можно сэкономить, по меньшей мере, байт на каждый экземпляр union-а. А когда таких экземпляров пара-тройка миллионов, то и экономия получается немаленькая. Особенно с учетом эффекта выравнивания данных.
Кто вам сказал, что работа с JSON и БД -- это тривиально? Если это в вашей реальности так, то это вовсе не означает, что это мной подразумевалось. Т.е. речь о ваших домыслах.
Не написал поскольку не имел дел ни с тем, ни с другим.
Прекрасно, где здесь высказывалась оценка что одно легче/сложнее лучше/хуже другого?
А теперь покажите пальцем, где бы я говорил и про "на C++ задачи огого", и, особенно, про "интеллектуального превосходства".
Что-то вы себе выдумали, а потом в этом обвинили собеседника.
Речь как раз и шла о том, что решая разные задачи на разных языках вам нужны разные возможности. Поэтому ничего удивительного в том, что в C# вам не нужны фичи C++.
Зачем из таких очевидных вещей устраивать цирк с "интеллектуальным превосходством" -- хз.
Просто удивительно как такое светило снизошло своей милостью до общения с плебсом.
Вы бы взяли труд подумать о том, о чем именно вас спросили.
Легко представить, что на C# вы берете JSON-ы и перегоняете их в БД, или в обратном порядке.
Тогда как на C++ вы занимаетесь анализом видеопотоков или deep packet inspection.
И это практически непересекающиеся области. Т.е. в C++ вам нафиг не нужно иметь LINQ, тогда как в C# вам не нужны C++ные шаблоны со специализацией под узкие конкретные случаи. Откуда и проистекает "Я пишу на С++ и шарпе и еще ни разу в шарпе мне не потребовалась функциональность из С++".
Но если вы и на C++, и на C# занимаетесь одинаковыми задачами, то было бы интересно послушать что же это за задачи такие.
Вы еще скажите, что делаете на C# тоже самое, что делаете на C++.
Боюсь, вы задаете вопрос не тому человеку :)
Что касается моноброви, то, как по мне, то это лучше, чем изначальное использование одинарной "крышки". Т.е. планировалось
^Type
, сейчас хотя бы^^Type
, что и заметно лучше, и не вызывает диссонанса с уже имеющимся в C++operator^
.Что касается
[: :]
, то вроде бы это распространенная тема в различных template engines, когда есть специальные маркеры, отличающие текст самого шаблона, от места подстановки генерируемого текста. И это удобно. Код вида:хоть и неважно читается из-за плохого выбора набора символов, но все-таки гораздо лучше условного:
PS. И да, ужас в виде
co_await
иco_return
-- это еще один пример того, что у комитета со вкусом как-то не очень :)))Да что угодно, если уже все это заключается в квадратные скобки:
[~ ~]
,[@ @]
,[# #]
,[* *]
. Можно было бы, наверное, и^
задействовать, типа[^ ^]
, раз уж "крышечка" просочилась в рефлексию, и оно бы было бы даже логичнее, но тогда, боюсь, кто-то напишет[^^^something^]
.Лично я бы выбирал между:
[@ template_arguments_of(type_of(^^name))[1] @]
[# template_arguments_of(type_of(^^name))[1] #]
но мои вкусы несколько специфичны ;)
Возможно, у вас и у тех, кто пришли в C++ минуя чистый Си.
Интересно, а в комитете всех устраивает использование оператора "баян", т.е.
[: :]
в рефлексии?ИМХО, так это чуть ли не максимально нечитаемая комбинация из тех, что можно было придумать. Двоеточия на фоне квадратных скобочек не считываются :(
Ага, отличный пример того, как десятилетиями прятать голову в песок под мантры "bad_alloc-а не бывает, после bad_alloc-а жизни нет".
А можно ли в Qt-шном коде безопасно вызывать
std::vector::at
илиstd::optional::value
?Пока с наглядными примерами надежного кода без исключений у вас не получается. Еще попробуете?
Зря вы прибегаете к аргументам "зато у вас негров линчуют", клоуном от этого вы быть не перестаете, скорее наоборот.
что если факты противоречат гипотезам, то тем хуже для фактов. В Go паники спокойно перехватываются, а как раз defer-ы позволяют чистить ресурсы для того, чтобы продолжить после восстановления без утечки чего-либо.
"прекрасно" -- это сильно (очень сильно) преувеличено. Но вот то, что это очень дорого и очень многословно -- это да.
Пока от вас не увидел ни одного.
А мне как раз понятно почему вам непонятно.
Надежность моего кода зависит от того, как я его написал. При этом я не несу ответственности за то, что кто-то как-то написал с использованием моего кода. Так что этот звидежь отправляем в /dev/null.
А мне и не нужно ловить все исключения из каждой функции. Вот чего не понимаю упоротые противники исключений, так это того, что исключения ловятся гораздо реже, чем бросаются.
Это какая-то страшилка из 1990-х. В современном мире, когда проекты собирается из open-source компонентов, такой проблемы не существует как класса. Более того, очень много C++ных проектов вообще затачивается по один единственный компилятор.
Ирония в том, что анонимом в данном разговоре являетесь вы.
Кроме outcome есть еще и Boost.Leaf.
Абсолютно.
Может быть, но мне интересно посмотреть на то, как пишут код настолько упоротые противники исключений.
Время от времени приходится. Там либо забивают на часть возможных проблем (например, часто не контролируются результаты strdup или sprintf). Либо же сразу вызывают
abort
и все.Там сплошное
if err != nil
из-за которых прикладная логика теряется под толщей подобных if-ов и, плюс к тому, в Go есть паники.То, что вам не понятно -- это очевидно. Но вопрос не в этом, а в том, как писать надежный код без исключений на C++ (не Rust, не Go, а именно на C++). И примеров, как я понимаю, от вас не будет.
А ваш код где-нибудь в открытом доступе есть? Очень хочется посмотреть как люди пишут надежный код только на кодах возврата, совсем без исключений.