Привет, Хабр! Меня зовут Дмитрий Луцив, я работаю в СПбГУ на кафедре системного программирования и в лаборатории компании YADRO, веду ряд IT-дисциплин на математико-механическом факультете и помогаю вузам актуализировать образовательные программы под задачи индустрии.
Я давно не программировал на С++, но стараюсь не отставать от изменений, происходящих в языке. Книга «C++ 20 в деталях» заинтересовала меня личностью автора (на секунду, это Райнер Гримм — автор множества книг по C++, блогер, докладчик на десятках тематических семинаров) и возможностью познакомиться с новым источником знаний о «плюсах». Решил ее прочитать, чтобы понять, кому материал будет полезен, и могу ли я его рекомендовать. Под катом расскажу, что в книге хорошего, а что можно было бы сделать лучше, а также дам список дополнительных источников для специалистов разного уровня.
Краткое содержание
«С++ 20 в деталях» — перевод на русский язык книги Райнера Гримма «C++ 20: Get the Details». Перевод и научную редактуру выполнили мои коллеги, преподаватели МИЭМ ВШЭ.
Книга начинается с экскурса в историю языка С++. Затем автор делает краткий обзор новых возможностей C++20: концептов, модулей, новой библиотеки диапазонов, корутин, оператора трехстороннего сравнения, нововведений в стандартной библиотеке и в поддержке параллельности.
Следом идет несколько глав, в которых темы раскрываются подробно.
Концепты. При обобщенном программировании типы и функции можно параметризовать во время компиляции другими типами или значениями. Эти параметры, в свою очередь, тоже должны соответствовать каким-то требованиям. Концепты позволяют обеспечить это, задавая условия на параметры обобщенных классов и функций. Это довольно мощная возможность. Концепты напоминают классы типов в языке Haskell, известном строгостью типизации.
Модули. Позволяют минимизировать или исключить использование препроцессора и ускорить сборку больших программных проектов.
Оператор трехстороннего сравнения. Позволяет компактно задавать упорядочивание пользовательских типов, аналогично
__cmp__
из Python или функциям сравнения для C, но реализованный строго в плане типов.Назначенная инициализация. Это изменения и дополнения, которые касаются возможностей инициализации составных и контейнерных типов в коде программы. Очень не хватало, если сравнивать со многими другими языками!
consteval
иconstinit
. Конструкции, фактически позволяющие использовать элементы суперкомпиляции в C++. Если какие-либо значения известны на этапе компиляции, то все, что зависит исключительно от них, можно посчитать еще до исполнения программы.Улучшения и изменения шаблонов, лямбд, добавление новых атрибутов и прочие небольшие, но удобные изменения в языке.
Изменения и добавки в стандартную библиотеку: поддержка работы с диапазонами (а-ля
range
в Python), изменения в контейнерах, работа с календарем.Корутины (сопроцедуры). Долгожданная возможность, позволяющая писать асинхронные программы без использования потоков. Экономит системные ресурсы, естественным образом использует асинхронные возможности ввода-вывода.
Прочие возможности параллельного программирования, связанные с использованием потоков и механизмов синхронизации, с моделями памяти.
Во всех главах автор приводит подробные и объемные примеры программного кода. Из-за важности параллельного и асинхронного программирования в книге есть отдельная глава «Практические примеры». И хотя примеры в ней носят учебный, а не производственный характер, они показывают использование C++ в уже вполне «взрослых» ситуациях.
В конце можно ознакомиться с тем, что, по мнению автора, ждет нас в C++23. На момент публикации ожидалось следующее:
новые возможности стандартной библиотеки,
поддержка контрактов,
описание пред-, постусловий и инвариантов для более жесткого контроля исполнения программ и сопоставления с образцом (оператор
inspect
, более мощный, чемif
иswitch
, по возможностям аналогичныйmatch
в функциональных языках).
Не все ожидания Райнера Гримма и переводчиков оправдались. О том, какие изменения произошли в новом стандарте языка, поговорим на митапе по С++ 21 ноября. Илья Казаков, инженер по разработке ПО в YADRO, расскажет, какие боли закрываются, а какие — появляются в новом стандарте С++ 23. Участие в митапе бесплатное, достаточно зарегистрироваться по ссылке.
Следует отметить, что несмотря на то, что некоторые новые возможности языка описаны в стандарте, они все еще не реализованы в полной мере компиляторами и стандартными библиотеками. В особенности это касается модулей — наиболее значимого на мой взгляд изменения. Их цель — оторваться от препроцессора и унаследованной от C и языка ассемблера модели раздельной компиляции и реорганизовать трансляцию больших программных проектов так, как это сделано в более современных языках. Актуальные компиляторы не могут полностью реализовать стандарт С++: в той или иной мере это несоответствие наблюдается на протяжении последних 25 лет.
Что хорошего в книге
Обзор новых возможностей C++ вначале
Позволяет сформировать первое впечатление о манере изложения и о том, что можно почерпнуть из книги, а что нет.
«Важные замечания» в конце каждого раздела
В оригинале — Distilled Information, то есть «дистиллят» изученного, то, что можно выделить в сухом остатке. Это краткие тезисы, которые помогают «собрать мозги в кучу» и четко зафиксировать то, что мы только что узнали. Вот пример:
Перевод и оформление
Переводы технической литературы иногда бывают такими, что хватаешься за голову, бежишь читать оригинал и не возвращаешься. Но в данном случае и он, и научная редактура выполнены твердой университетской рукой — решения выглядят взвешенными, на них можно положиться.
По оформлению русскоязычная версия местами превосходит оригинал, в значительной степени основанный Райнером Гриммом на подборке материалов из собственного блога. Вот пример:
Казалось бы, чепуха. Но, когда читаешь нетривиальный пример кода с пояснениями, видишь скриншот консоли с результатами работы программы (иногда неожиданными!), а текст прочитать не можешь, разве это пустяк?
Что бы сделало книгу лучше
Более информативные иллюстрации
Большинство иллюстраций появляются в начале разделов и изображают Сиппи в каком-нибудь забавном виде. В оригинале — Cippi, маскот книги, нарисованный супругой Райнера Гримма. Имя персонажа созвучно с «CPP».
Редактор русского перевода в предисловии написал, что подписи к рисункам катастрофически неинформативны: «Было желание убрать все эти бессмысленные рисунки из книги, но, в конце концов, было решено смириться с этим».
С информативностью у Сиппи действительно беда. Картинки выше предваряют главы про новые возможности C++ 20: модули (левая иллюстрация), корутины (правая). Пользы никакой, а правая иллюстрация так вообще скорее дезориентирует. С другой стороны, книги по C++ — в принципе не самое легкое чтиво, а небольшая добавка бессмысленного абсурда слегка разгружает читателя. Так что хорошо, что Сиппи пережила перевод и научное редактирование и никуда не делась.
Некоторые иллюстрации более-менее информативны, но «плотность» информации в них все же вызывает сомнения. Вот пара примеров. Стоило ли ради этого рисовать отдельные картинки?
Бросается в глаза, что у иллюстраций нет единого стиля, но это обусловлено тем, что материалы англоязычной версии автор взял из личного блога. В интернете разобщенные картинки выглядят привычно и уместно, но в формате книги — уже нет. Издание бы только выиграло, если бы схемы перерисовали и перевели на русский язык.
Периодически попадаются и информативные примеры:
Но она не авторская и вообще относится не к C++, а к Haskell.
Качественные иллюстрации для сложного текста очень важны — они помогают его лучше понять. Надеюсь, в будущих редакциях книги или перевода Сиппи и сама получше разберется в C++, и поможет сделать это читателю. Например, покажет не только забавные картинки из жизни персонажей детских книжек, но и доходчивые диаграммы, поясняющие тяжелый материал.
Нереализованная возможность содержательно проиллюстрировать книгу — пожалуй, самый существенный недостаток. И в переводе он не был исправлен.
Примеры кода, с которыми удобно работать
Незначительный недостаток — с кодом в книге неудобно работать. Что с ним можно сделать? Перепечатать вручную, сохранить в файлах, откомпилировать... Но ведь у автора есть репозиторий на GitHub с примерами из книги. Однако на него не ссылаются ни в оригинале, ни в переводе. Почему его прячут — большая загадка.
Пока приходит в голову лишь одна слегка безумная идея. И автор, и переводчики надеются на то, что читатель вручную наберет какие-то фрагменты кода и в итоге лучше усвоит материал.
Кому книга будет полезна
«С++ 20 в деталях» ориентирована в первую очередь на опытных программистов и архитекторов — тех, кто уже знаком с C++, практикует его использование и знает практическую цену описанным нововведениям. Да, автор рассказывает, зачем нужно конкретное обновление, где от него станет лучше. Но для полноценного понимания необходимо больше контекста из практического опыта. Искушенный читатель не раз подумает: «Да, это как раз то, чего мне не хватало!»
Тем, у кого опыта программирования на C++ нет или почти нет, я бы рекомендовал присмотреться к другим книгам и активностям. Это могут быть:
Любые книги по программированию на C, если это тоже в новинку. Хотя современный C++ зачастую не поощряет использование конструкций и приемов C, иметь о них полноценное представление все же необходимо. Точно не ошибется тот, кто выберет «Язык программирования Си» Б. Кернигана и Д. Ритчи.
онлайн-курс на Stepik от CS-центра (базовый курс и его продолжение)
книга Скотта Мейерса «Эффективный и современный C++»
И, конечно, лучшим дополнением теоретических знаний станет практический опыт программирования на C++.
Книга «С++ в деталях» вышла в серии «Книжная полка истового инженера». При поддержке МИЭМ и ВШЭ мы помогаем с публикацией профессиональной литературы по проектированию и разработке микро- и радиоэлектроники, программированию и технологиям производства. Посмотреть, какие еще книги есть на «Полке», и заказать любую из них можно на маркетплейсах, в онлайн-библиотеках или по ссылке.
Райнер Гримм называет свою книгу «справочным руководством». И, на мой взгляд, зря: для таких целей лучше заглянуть на C++ Reference. Для справочной литературы материал слишком «плавный»: его комфортно читать от корки до корки, проникаться идеями. Искать же в ней какие-то детали — занятие небыстрое.
Что еще изучить по теме
Книга мне понравилась, но ограничиваться ею точно не стоит. Сложные для понимания вещи часто требуют изучения нескольких источников. Разные авторы обычно с разных сторон смотрят на одни и те же вопросы. Прочитал две статьи вместо одной — получил «стереоизображение» вместо плоской картинки.
Какими источниками стоит дополнить книгу?
Обязательно следует смотреть на примеры автора и читать его блог.
Про корутины, когда они только появлялись в C++, IT-специалисты поговаривали, что «авторы стандарта превзошли себя, теперь уж точно никто ничего не поймет». Так что по этой теме лишней информации не бывает. Добавим следующие источники:
В более сжатом, но толковом виде с нововведениями C++ 20 можно познакомиться на Хабре в цикле статей Яндекс.Практикума:
Когда приобретаешь новые знания о не самом простом языке программирования, первым тебя обычно оценивает транслятор. Чтобы избежать сюрпризов, стоит читать документацию конкретных компиляторов и прочих инструментов. Например, документацию CLang по модулям. Здесь мы видим, что новые возможности реализованы не полностью. Кстати, автор книги больше всего хвалит компилятор компании Microsoft, поэтому описанием его реализации модулей точно пренебрегать не стоит.
Добавлю в тему корутин и модулей. Здесь следует изучить примеры, подтверждающие, что это уже не «вещи в себе». То есть в C++ не просто решили «сделать, как у других, и положить на полку», а добавили действительно востребованную функциональность. Свидетельством актуальности и готовности к применению корутин в работе могут выступить:
библиотека IOneRing, предоставляющая интерфейс с использованием корутин C++ к подсистеме асинхронного ввода-вывода Linux io_uring,
отдельный небольшой проект, по которому мой коллега из YADRO Илья Казаков сделал тематический доклад на конференции C++ Russia.
Модули тоже не остаются без внимания. Их поддержка находится в экспериментальном состоянии почти везде, но в популярной системе сборки CMake модули уже поддерживаются. Достигнутые результаты пришли не моментально: вот пример более чем трёхлетней дискуссии (с весны 2020 до лета 2023 года) на StackOverflow.
Наконец, стоит изучать основные возможности и следить за изменениями других языков программирования: Java, C#, Python, Go, Rust. Сравнивайте их с С++, изучайте реализацию — так вы лучше поймете этот язык. Этот совет, конечно же, универсальный и работает во все стороны: кто решит освоить Rust — не ленитесь оглядываться и на «плюсы».
Комментарии (14)
mao_zvezdun
01.11.2023 11:45+3Имею это издание в бумажном виде, про содержание ничего плохого говорить не буду, но оформление ужасное. То, что в "оригинальном авторском pdf" такая же сверкающая каша скриншотов разнокалиберных терминалов, не оправдание, я считаю. Можно было бы локализовать и это, оформив текстовый вывод программ в виде текста же. И нужно было это сделать, потому что почти каждый скрин на любой странице - это кровь из глаз. И пример сообщений об ошибках на стр.99, где текст в картинке настолько мелкий, что там не разобрать вообще ничего. И код на странице 163, где две строчки
sqr(5) : 25
sqr(a) : 25
нарисованы скриншотом на половину страницы. И такая дичь не единичные примеры из ряда вон, а "общий стиль".
Исходники набраны огромным шрифтом, из-за чего простейший пример расползается на целую страницу, а то и две. В исходниках тоже нет единообразия - какие-то напечатаны одним кеглем, рядом на соседней странице уже другим, где-то есть нумерация строк, где-то нет.
В общем, читать тяжело. Может быть, конечно, на это и расчёт, чтобы читатель не бежал в комфортном режиме взглядом по строчкам, а продирался сквозь оформление с чувством и паузами на отдохнуть-подумать. Но скорее всего просто сделали в режиме "и так сойдёт"
dluciv Автор
01.11.2023 11:45+1В переводе хотя бы инвертировали терминалы, мне лично это много дало ????. Расчёт едва ли был. Как и с отсутствием ссылок на ГитХаб.
mao_zvezdun
01.11.2023 11:45+7Вот несколько примеров страниц, взятых почти наугад, если ещё полистать можно еще таких же добавить, да там все такие.
Wallhead
01.11.2023 11:45+1Автору платили построчно, поэтому слуга Дартаньяна говорил односложными фразами, но которые занимали всю строку!
voldemar_d
01.11.2023 11:45+1книга Скотта Мейерса «Эффективный и современный C++»
Книга хорошая, но надо иметь ввиду, что там про C++11 и C++14.
dluciv Автор
01.11.2023 11:45+2Да, но для изучения в отсутствие опыта вполне годится. Жаль конечно, что про 17 и дальше он уже не писал.
amberovsky
01.11.2023 11:45+1Книгу не читал, скриншоты запостили, конечно, забавные, но некритичные.
Переводить техническую литературу, как было подмечено в статье - боль/страдание и перевод технических терминов в другой язык гарантировано будет проблема. Особенно учитывая, что много кто (если не большинство), в связи с работой с англоговорящими коллегами будет использовать английский вариант.
sw0rl0k
01.11.2023 11:45+3Есть на мой взгляд простое решение этой проблемы. Если у английского термина нет общепринятого русского перевода, то при первом упоминании этого термина в тексте надо давать в скобках английскую версию.
kolya7k
01.11.2023 11:45Вы меня, конечно, простите, но любой опытный программист читает любую техническую литературу на английском лучше, чем на русском. Так что этот перевод ориентирован на неопытных как раз, которые предпочтут русский. Я, например, всегда выбираю Английский для технических книг, статей, документации, потому что перевод на русский в 100% случаях корявый..
Кстати да, для designated initializers лучше подходит перевод «именованные инициализаторы», но тут косяк скорее в самом стандарте, в других языках такой тип инициализации называется как раз named initialization.
dluciv Автор
01.11.2023 11:45Когда перевод нормальный, почему бы и на русском не почитать? Для разнообразия хотя бы, знание русского языка освежить ????. Да и языку, в плане его развития, на пользу идут технические и научные тексты, на нём написанные ????
tenzink
Долго вытался понять из названия, что такое "Назначенная инициализация". Потом понял, что речь про вот это https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers. Я понимаю, что designated переводится как "назначенный", но получается как-то уже очень неинтуитивно. Сталкивался с переводом "обозначенный" в контексте языка C, который тоже кажется не очень удачным.
Интересно, есть ли какие-нибудь ещё варианты перевода. Может поискать в других языках программирования (например в C# похожая конструкция с with)? Мне пока приходят только варианты перевести "выборочная", "уточняющая" или "именованная инициализация".
dluciv Автор
Вот сходу не сказать. Она же действительно и выборочная, и уточняющая, и именованная ????. С переводом терминов вообще часто тяжело. Типичная первая мысль: «Ну что за ерунда, я бы лучше придумал!..» А как попробуешь действительно придумать, понимаешь, что переводчики тоже голову поломали, пока пришли к тому или иному решению. Если альтернатива и приходит в голову, то как правило не сильно лучшая, и выбор — дело вкуса. Как с «картинками» и «сопроцедурами», например.
Miceh
"именованная инициализация" выглядит более уместной с учётом того, что уже есть понятие "передача параметров по имени"
dluciv Автор
В этих двух случаях «имя» обозначает совсем разные вещи. Как раз если бы не передача по имени, именованная инициализация была бы уместнее. А так запутать легко будет...
Но это частное моё мнение, на объективность претендовать не могу.