Предупреждение: внизу будет зашкаливающе душный пост. Заходить в костюме химзащиты!
Недавно набрёл на книгу с обложкой выше (увы, не первой, а второй) и чего-то название продало мне её. Увы, обложка - лучшее, что в ней есть.
Я вообще в сложных отношениях с книгами по плюсам, так как я человек, который искренне обычно надеется, что вот сейчас выйдет книга, в которой покажут, как разрабатывать быстро, легко и получить донельзя элегантный и компактный код. Последний раз такое было с знаменитым трудом Александреску - там для меня в своё время открывались горизонты, просто читал и обалдевал: "а что так можно?". С тех пор, конечно, много воды утекло, но я всё равно жду чего-то аналогичного. Но, увы, как новые стандарты (начиная с C++14), так и издания по плюсам меня лишь разочаровывают. Не стал исключением и сей труд.
Условный блог OTUS на Хабре похвалил книгу, но, я, к сожалению, могу лишь поругать - она годится для каких-то полных новичков, которым она будет неинтересна. Потому что они и сами могут почитать C++ Core Guidelines (против которого, я ничего не имею), и, собственно, примерить их на себя. Существующие проекты и так могут адаптировать, и там народ достаточно опытен, чтобы и сам разобраться, что к чему.
Сейчас условный читатель спросит: а какое я вот право имею её ругать? Там целый Страуструп её похвалил, авторы увешаны регалиями, а вот я кто такой? Согласен - я х** с горы с несчастными 4 годами коммерческой разработки (и, помимо этого, около 6-8 некоммерческой). Я, конечно, ракеты в космос на плюсах не запускал - авторы тоже вряд ли это делали. И некоторые высказывания в книге вызывают, как минимум сомнения, и я хочу их привести.
Я начну со с. 34. Авторы говорят: "Стандарт C++ однозначен, и это одна из причин, по которой его трудно читать". Вообще, это классно, но если это так, то почему модули имеют мелкие различия в синтаксисе у GCC и у MSVC? А значит, уже не всё так хорошо. Кроме того, он огромен, и в самом FAQ по стандарту написано, что это скорее "договор" о том, как должен быть реализован компилятор плюсов. В общем, уже и так не всё однозначно, я сама дочь компилятора. А уж если пройтись по спискам багов GCC и Clang можно и вовсе поседеть.
И на следующей же странице книга вляпывается в дикий холивар, ибо она касается #pragma once. Замечу, что сама рекомендация CppCoreGuidelines предлагает использовать include-guards, в которых всегда можно неплохо накосячить. И здесь это даже не проблема книги, а стандарта. Да, я серьёзно. Люди, предлагающие такое решение, не могут определиться, что такое "подключи мне сей файл один раз и потом до конца TU больше никогда не включай". Аргументы в книге просто эпичные, позволю себе привести их.
"Все компиляторы, которые авторы использовали за последние 20 лет, реализуют эту директиву pragma, но задумаемся: что она означает на самом деле? Может, «остановить синтаксический анализ, пока не будет достигнут конец файла»? Или «не открывать этот файл во второй раз»? "
Это очень слабый аргумент, потому что его решение можно свести к "тупой компилятор, сгенерируй мне include guard вот здесь и выполняй его". Справедливости ради существуют эпичные треды на реддите ([1], [2]), где приводятся более серьёзные аргументы с симлинками и сетевыми хранилищами. Но я ни разу не встречал, чтобы мне хотелось, чтобы файл по симлинку вставился второй раз. А уж проверить пути - ну это же невыполнимая задача, ага. Доп. аргумент - это вставляет в ваши заголовки и логику компиляции, семантику файлов. Ну это вообще жесть. Файлы существуют. Файлы будут существовать, как концепт, и пока никуда не планируют деваться.
Ладно, может, несмотря на предложение авторов выше, #pragma once плохо поддерживается? Сверяемся с вики, а там из неподдерживающих только Solaris C++. Я не могу серьёзно воспринимать тут IDE, у которой последняя версия была аж в 2017 году, да ещё и довольно своеобразную. Ну и куча крупных проектов этому совету не следует, поэтому, как по мне, - лучше, наконец, втащить инструкцию в стандарт и перестать валять дурака. Почему модули там есть, а такой мелочи до сих пор нет?
Многие скажут: ну и чего я прицепился к этому? Так это же начало книги, начало самое! Такие назидания уже создают скверную ситуацию, когда хочется бросить её и не вспоминать ни о чём таком.
При этом уже на следующей странице говорится, что в силу нормативных ограничений "Очевидно, что становится всё более необходимо шире и чаще использовать стандарт ISO C++". Извините, но, во-первых, не следует (нормативные ограничения ограничивают и стандарт, что иллюстрируется выше запретом на динамическое выделение), а во-вторых, то, что Boost сам по себе запрещён где-то, не значит, что какое-то ограниченное подмножество буста не удастся втащить в проект и адаптировать.
Не всё ужасно - далее в принципе идут внятные и здравые советы, которым вполне можно и нужно следовать.
Очередная проблема настигает меня в главе 1.4, где предлагается отказаться от простых геттеров и сеттеров в пользу публичных полей. Ух, начну с того, что в принципе там есть историческая сноска про инкапсуляцию в ООП, хоть и неполная. Я помню, что было много интересного, потому что была идея, как у авторов, что сеттеры должны проверять инварианты класса и содержать умную и сложную логику. Потом оказалось, что при чтении кода (90% времени программиста) люди обалдевали от того, что, сеттер делал ЧТО-ТО НЕ ТО и появилась рекомендация делать сеттеры примитивными, а для таких приколов заводить отдельные методы с более сложными именами, чем "set_x". И, будь я лет на 6-7 моложе, я бы сказал: "да, зашибись, к чёрту эти примитивные сеттеры и геттеры, ещё и производительность портят в дебаге". Но вот при отладке встаёт задача - найти тот момент, когда поле А принимает значение Х. И вот тут сеттеры нам помогают — ставим breakpoint в сеттер, вуаля, ловим все такие моменты. Можно ещё и breakpoint с условием сделать, чтобы вообще было отлично. Без этого тяжело. Может, я не прав и, к примеру, GDB имеет такой функционал из "коробки"? Ну, в GDB ([1], [2]) можно повесить watch на запись в адрес определённой переменной. Но если вам надо все случаи — то остаётся надеяться, что IDE достаточно умна, чтобы найти все доступы к полю. Это хорошо, если проект мал, но в сложных случаях - куча работы из-за такой рекомендации, а то и проблемы, если что-то упустить. Это будет хорошо, если описанная мной ситуация никогда не возникнет (тогда, пожалуйста), но получается, что рекомендация имеет существенные ограничения.
Далее в принципе идут адекватные советы, тривиальные и логичные вещи. Но в 3.1. авторы снова принимаются за странные высказывания. Я позволю себе привести цитату полностью:
"По умолчанию для хранения динамических объектов следует использовать std::unique_ptr, а тип std::shared_ptr должен использоваться, только если рассуждения о времени жизни и владении невероятно запутаны. Но даже в этом случае применение типа std::shared_ptr следует рассматривать как признак технической недоработки, обусловленной несоблюдением соответствующей абстракции."
Что здесь не так? Как по мне, существует большое количество случаев, когда "рассуждения о времени жизни и владении объектов и невероятно запутаны". Ну, хотя бы скриптинг, в том числе и в играх. Ну ок, мы можем сказать, что объект игры - самый большой собственник всего, что в ней происходит. Дальше мы начинаем экономить память, ходить по ссылкам, и вуаля - мы придумали сборщик мусора. Здесь, скорее всего, просто неудачная формулировка предложения - имелось в виду, что если мы можем использовать unique_ptr, лучше всегда его и использовать. Это ок вариант, так-то.
Глава 4.4. презентует нам не самый лучший случай использования [[no_discard]] - его предлагается навесить на условную проверку строки на непустоту. Это просто странное решение - если человек проигнорировал возвращаемый тип в таком случае, то, он, конечно, сам себе злой Буратино. Но есть же пример куда лучше - такое бы на fopen навесить. Там и последствия игнорирования возвращаемого типа куда серьёзнее, утечка ресурса, как-никак.
Дальше, к счастью, идут нормальные вещи. Конечно, про "красивый C++" речи нет - код-стайл прыгает, нас гонят по, в некоторой мере, "положняку" по тому, как авторы видят плюсы. Ну хорошо, но зачем было называть это "Красивый C++", я, к несчастью, не понял, в следовании этим рекомендациям особо красоты нет, лишь безопасность.
Вообще, легко видеть, чего хочется авторам - сделать ультрабезопасное подмножество плюсов, где нельзя стрельнуть себе в ногу. Идея хорошая, но, временами, я думаю, что это борьба с ветряными мельницами. Для этого уже есть C#, Java, Python, и. т.д. Там всё хорошо, если нужно что-то низкоуровневое - любой из этих языков даёт возможность допиливать это "что-то" на плюсах. Попытка "отгрызть" здесь нишу может и не удастся, потому что С++ именно и хорош возможностью, если нужно, нарушить все правила и выиграть по производительности. Зажимать его в тисках такой логики - это, возможно, не самое лучшее решение. Есть вариант более хороший - делать Carbon, Cpp2 и прочие, собственно, это будет более хороший вариант.
Отдельно скажу, что неплохие исторические вставки из жизни и работы авторов читать интересно - и вот лучше бы это выделить в отдельную книгу, которая была бы более интересным чтением, чем "Красивый C++".
Цена книги - ну Amazon просит аж 33 доллара, но на условном Ozon цена падает до ~1700р, что более здраво, но всё ещё дороже, чем оно должно стоить.
Книгу не рекомендую. Можно посмотреть CppCoreGuidelines, если уж так и интересно, но тут на ваше желание - гайдлайнов разного рода для плюсов уже и так пруд пруди, можно выбрать на любой вкус и цвет.
Комментариев нет:
Отправить комментарий