Главная / Курсы / C++ по спирали / Что такое C++
# Глава 1. Что такое C++ C++ — это компилируемый, статически типизированный язык с прицелом на _эффективность._ На C++ можно писать драйверы, заточенные под конкретное устройство, а можно создавать высокоуровневую бизнес-логику кроссплатформенного проекта. C++ — универсальный язык, подходящий для решения практически любой задачи. При этом он позволяет выжать из железа максимум. Пока вы читаете этот текст, C++ код исполняется в дефибрилляторах, AAA-играх, СУБД, текстовых процессорах, поисковиках. И даже [в марсоходе](https://www.youtube.com/watch?v=3SdSKZFoUa8) Curiosity: ![Ровер Curiosity. На борту C++!](https://raw.githubusercontent.com/senjun-team/senjun-courses/refs/heads/main/illustrations/cpp/mars_rover_curiosity.jpg) {.illustration} За эффективность и универсальность C++ приходится платить: - высоким порогом входа в язык, - скоростью разработки, - количеством деталей, о которых задумывается разработчик, чтобы писать качественный код. ## Философия С++ За свою 40-летнюю историю C++ стал одним из самых распространенных языков в мире. Секрет популярности кроется в философии C++. Она ставит во главу угла несколько принципов. ### Свобода выбора Язык не навязывает «единственно верного» пути. Вы можете вручную управлять ресурсами и контролировать каждое выделение памяти. А можете использовать удобные и высокоуровневые средства стандартной библиотеки. Если на ваш проект хорошо ложится обработка ошибок через исключения — пользуйтесь ими! Хотите работать со старыми-добрыми кодами ошибок? Пожалуйста. Понимаете, что такое алгебраические типы данных? Найдется и такое. Если вы пришли в мир C++ из Go, то почувствуйте разницу. C++ предоставляет широкий арсенал возможностей. От разработчика же требуется наличие здравого смысла и некоего багажа знаний. Конечно, у такого богатства есть и обратная сторона: с годами C++ окончательно укоренился в роли самого сложного из мейнстримных языков. С++ часто сравнивают со швейцарским ножом. _Очень многофункциональным_ швейцарским ножом. ![Мультитул C++](https://raw.githubusercontent.com/senjun-team/senjun-courses/refs/heads/main/illustrations/cpp/multitool.jpg) {.illustration} ### Обратная совместимость Обратная совместимость — это возможность собрать старый код новым компилятором. Или, например, подключить к новому проекту библиотеку, написанную 30 лет назад. Фичи и улучшения вносятся в C++ предельно осторожно. Поломка обратной совместимости может быть _единственной_ причиной для отказа от ускорения контейнера из стандартной библиотеки на 10%. Из-за упора на обратную совместимость синтаксис С++ и стандартная библиотека порой выглядят неконсистентно. А устаревшие фичи остаются с нами надолго. Значит, обратная совместимость — скорее недостаток, чем достоинство? Не совсем. Назовите, какой еще язык способен похвастаться таким количеством старых проектов, живущих и развивающихся и по сей день? Наверное, только Си. Порой при внесении изменений в язык на обратную совместимость все же закрывают глаза. И пример тому — замена внутренней реализации класса строки `std::string` в C++11. ### Эффективность **Вы не платите за то, что не используете.** Например, в языке нет встроенных проверок выхода за границы массива, ведь в ряде случаев они избыточны. В остальных же случаях разработчик должен организовать их самостоятельно. Абстракции с нулевой стоимостью (zero-cost abstractions) делают код простым и понятным. А компилятор оптимизирует его так, чтобы он не уступал своему низкоуровневому аналогу. То есть стоимость у таких абстракций все-таки имеется, но взимается не в рантайме, а при компиляции. Поэтому более точное название этих абстракций — **абстракции с нулевым оверхедом** (zero-overhead abstractions). Рассмотрим пример такой абстракции. Возьмем динамический массив `numbers`, содержащий целые числа. Нужно пройтись по массиву и поместить каждое число в диапазон: если оно меньше нуля, приравнять к нулю. Если больше 100 — сделать равным 100. Пройдемся в цикле по индексам массива и применим это условие к каждому элементу: ```cpp {.example_for_playground .example_for_playground_001} std::vector<int> numbers = random_vector(); for (std::size_t i = 0; i < numbers.size(); ++i) { if (numbers[i] < 0) { numbers[i] = 0; } else if (numbers[i] > 100) { numbers[i] = 100; } } std::println("{}", numbers); ``` ``` [100, 72, 3, 0, 100, 100, 100, 45, 100, 100] ``` Нажмите на кнопку «Открыть в Playground» в верхнем углу этого примера. Вы увидите расширенный фрагмент кода, к которому добавлено измерение времени выполнения. Запустите его. В этом коде мы должны уделять внимание низкоуровневым деталям: - Допустимо ли использовать индексы для итерирования по контейнеру данного типа? - Не закралась ли ошибка при работе с индексами? Решим эту задачу иначе — с применением абстракций. Напишем функцию `clamp_to_pct()`, которая изменяет целое число по заданным правилам. Внутри она вызывает функцию стандартной библиотеки `std::clamp()`. Ознакомьтесь с ее описанием [на сайте cppreference.com.](https://en.cppreference.com/w/cpp/algorithm/clamp) Это лучший справочник по C++, и вы часто будете в него заглядывать. ```cpp void clamp_to_pct(int & n) { n = std::clamp(n, 0, 100); } ``` А теперь заменим цикл на вызов функции стандартной библиотеки `std::for_each()`. Она применит `clamp_to_pct()` к каждому элементу массива: ```cpp {.example_for_playground .example_for_playground_002} std::vector<int> numbers = random_vector(); std::for_each(numbers.begin(), numbers.end(), clamp_to_pct); std::println("{}", numbers); ``` ``` [100, 72, 3, 0, 100, 100, 100, 45, 100, 100] ``` Мы ввели несколько абстракций: собственную функцию `clamp_to_pct()`, [функцию высшего порядка](https://ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F_%D0%B2%D1%8B%D1%81%D1%88%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BA%D0%B0) `std::for_each()` и итераторы `begin()` и `end()`. Итератор — это объект, позволяющий перебирать элементы контейнера и поштучно предоставлять к ним доступ. В нашем случае итераторы послужили заменой индексам. Этот код выглядит высокоуровневым. Он: - Ограждает от потенциальных ошибок при работе с индексами. - Позволяет забыть о внутренней организации итерируемого контейнера. - Сконцентрирован только на бизнес-логике. Казалось бы, количество абстракций возросло, и это ударит по производительности. Но произошло все с точностью до наоборот. В релизной сборке второй вариант работает быстрее, чем первый! Не верите? Убедитесь сами: откройте этот код в плэйграунде и сравните время выполнения обеих реализаций. Но помните, что _не любая_ абстракция языка имеет нулевой оверхед. ## Что делает язык C++ языком C++ Рассмотрим ключевые особенности, на которых строится C++. ### Слабая статическая типизация Типизация в C++ статическая, слабая. Есть автоматический вывод типов. **Статическая типизация** гарантирует, что переменная связывается с типом в момент объявления. После этого тип переменной не меняется. Это отличает C++ от языков с динамической типизацией, таких как Python и JavaScript. В них переменная связывается с типом в момент присваивания значения. Так, в C++ целочисленная переменная не может внезапно превратиться в строку. Компилятор просто не даст вам собрать и запустить такой код: ```c++ {.example_for_playground .example_for_playground_004} int len_km = 6; len_km = "six km"; // ошибка ``` ``` error: invalid conversion from 'const char*' to 'int' ``` Перед вами функция `get_price_with_discount()`. Она принимает два аргумента. Это число с плавающей точкой (цена товара `price`) и флаг `has_promocode`, свидетельствующий о наличии у покупателя промокода. Функция возвращает цену товара с учетом скидки. {.task_text} В ней допущена ошибка: указан не тот тип возвращаемого значения. {.task_text} Нажмите кнопку «Запустить», чтобы прочитать ошибку компиляции. {.task_text} Исправьте тип возвращаемого значения. {.task_text} ```c++ {.task_source #cpp_chapter_0010_task_0010} std::string get_price_with_discount(double price, bool has_promocode) { if (has_promocode) { return price * 0.9; } return price; } ``` Функция возвращает строку. Но в теле функции видно, что намерением было вернуть число с плавающей точкой. {.task_hint} ```c++ {.task_answer} double get_price_with_discount(double price, bool has_promocode) { if (has_promocode) { return price * 0.9; } return price; } ``` Статическая типизация на корню предотвращает целый класс ошибок, связанных с типами. Чем сложнее и обширнее кодовая база, тем очевиднее польза от статической типизации. У нее есть и еще одно преимущество. Компилятор обладает знанием о типах всех сущностей в коде, а следовательно, у него развязаны руки для оптимизаций. Это делает программу более эффективной в плане производительности и экономии ресурсов. **Слабая (нестрогая) типизация** означает, что в C++ допустимо неявное приведение типов. При **неявном приведении** (implicit cast) компилятор, следуя правилам языка, выполняет преобразование значений одного типа в значения другого типа. Например, приводит целые числа к числам с плавающей точкой и наоборот. Это отличает C++ от [Rust,](https://senjun.ru/courses/rust/chapters/rust_chapter_0010/) в котором неявное приведение запрещено, и попытка сложить целое значение с дробным приводит к ошибке компиляции. Неявное приведение типов обеспечивает гибкость в комбинировании данных и скорость разработки. С другой стороны, оно же — неиссякаемый источник ошибок. Пример неявного приведения типов: для преобразования числа с плавающей точкой в целое компилятор просто отбрасывает дробную часть: ```c++ {.example_for_playground .example_for_playground_005} int len_km = 6.8; std::println("{}", len_km); ``` ``` 6 ``` Предположите, что выведет этот код? Тип `bool` может принимать два значения: `true` либо `false`. Ему присваивается символ амперсанда. {.task_text} Вы можете воспользоваться подсказкой. Она доступна по кнопке со знаком вопроса. {.task_text} ```c++ {.example_for_playground .example_for_playground_003} bool x = '&'; std::println("{}", x); ``` ```consoleoutput {.task_source #cpp_chapter_0010_task_0020} ``` ASCII-код символа амперсанда — число 38. Срабатывает правило приведения целых к булевым значениям: 0 приводится к `false`, а все остальные числа — к `true`. {.task_hint} ```cpp {.task_answer} true ``` В C++ возможно и **явное приведение типов** (explicit cast). Есть специальная языковая конструкция и встроенные функции для явного указания, к какому типу требуется привести значение. ### ООП C++, как и любой популярный современный язык, позволяет писать код в разных стилях. Последние стандарты C++ особенно богаты на элементы функционального программирования. Но родным стилем C++ всегда был объектно-ориентированный. C++ зародился как надстройка над Си, добавлявшая всего одну возможность: классы. Язык так и назывался: «Си с классами». С тех пор C++ стал гораздо более мощным и продвинутым. Развивалась и поддержка ООП. В C++ она реализована через: - Классы с разграничением доступа к полям и методам. - Наследование, в том числе множественное. - Виртуальные функции. Это методы класса, которые переопределяются в классах-потомках так, что конкретная реализация метода подставляется во время исполнения, а не во время компиляции. ### Метапрограммирование Метапрограммирование (metaprogramming) — это написание кода, который порождает новый код. В той или иной степени оно реализовано во многих языках. Но мощно развитое метапрограммирование на этапе компиляции — знаменитая фишка C++. C++ — язык, на котором можно _генерировать и выполнять_ код в процессе сборки программы, а не после ее запуска. И это отличный пример абстракций с нулевым оверхедом. В C++ есть для этого три механизма: - **Шаблоны** (templates) предназначены для создания обобщенных алгоритмов без привязки к типам данных и константам. Разработчик пишет шаблонные классы и функции, а компилятор генерирует для них специализации. Введенные в C++20 **концепты** (concepts) делают шаблоны более удобными: они позволяют задавать ограничения для параметров шаблонов. - **Вычисления на этапе компиляции** (compile-time evaluation). С помощью ключевых слов `constexpr`, `consteval` и `constinit` на этапе компиляции можно вызывать функции, выполнять циклы и условия. - **Макросы** (macros). Макроподстановки в коде осуществляются еще до этапа компиляции, и отвечает за них препроцессор. Макросы достались C++ в наследство от Си. Они были полезны во времена, когда в C++ еще не ввели шаблоны, вычисления на этапе компиляции и другие более современные инструменты. В Modern C++ хорошей практикой считается избегать макросов. Код на макросах трудно отлаживать. А допустить в нем ошибку — наоборот очень легко. Зачатки метапрограммирования _во время исполнения_ (а не во время компиляции) в C++ тоже имеются. Например, можно проверить, установлено ли между классами отношение наследования, или получить типы аргументов функции. Это элементы **интроспекции** (introspection) — изучения свойств объектов в рантайме. Для более продвинутой интроспекции и кодогенерации в язык планируется ввести **рефлексию** (reflection) времени компиляции. С ее помощью можно будет изменять свойства объектов на этапе сборки кода. ## Развитие языка За плечами C++ долгих 40 лет эволюции. Не удивительно, что код, написанный на старом и новом C++, порой разительно отличается. Взгляните. Hello World на текущем стандарте языка C++23: ```cpp {.example_for_playground} import std; int main() { std::println("Hello World"); } ``` Мы импортировали модуль стандартной библиотеки `std` и вызвали функцию `println()`. Обе эти возможности появились в C++23. Поэтому данный пример соберется только [свежими версиями](https://en.cppreference.com/w/cpp/compiler_support#cpp23) компиляторов. А вот Hello World на C++17 — более старом и самом [распространенном](https://www.jetbrains.com/lp/devecosystem-2023/cpp/#OEcX) стандарте: ```cpp {.example_for_playground} #include <iostream> int main() { std::cout << "Hello World" << std::endl; } ``` Здесь вместо импорта модуля `std` используется макрос для подключения хедера `iostream`, а вместо функции `println()` — стрим (stream) для печати в стандартный поток вывода `cout`. Как все это работает, мы рассмотрим в следующих главах. Оба примера показывают, что строки обрамляются двойными кавычкам: `"Hello World"`. А одинарные кавычки в С++ используются для отдельных символов: `'H'`. В этом курсе мы делаем упор на последние версии C++, но не забываем об экскурсах в историю и о ремарках, в каком стандарте появилась та или иная фича. Ведь индустрия переходит на новые версии языка с инерцией в годы. А началось все с того, что в конце 70-х Бьерн Страуструп (Bjarne Stroustrup) впечатлился классами языка Simula, но остался недоволен его производительностью. Язык Си, с другой стороны, отличался быстродействием, но не способствовал удобному объединению данных и методов их обработки. ![Бьерн Страуструп](https://raw.githubusercontent.com/senjun-team/senjun-courses/refs/heads/main/illustrations/cpp/bjarne_stroustrup.jpg) {.illustration} Страуструп создал расширение Си и назвал его «Си с классами» (C with classes). Оно завоевало популярность, обросло функционалом и было переименовано в C++ (инкремент от Си, что намекает на преемственность). В 1998 году появился официальный стандарт C++98. С тех пор развитием языка занимается комитет по стандартизации, а новые версии C++ публикуются в виде стандартов. В наши дни новые стандарты выходят раз в 3 года. ![Таймлайн развития C++](https://raw.githubusercontent.com/senjun-team/senjun-courses/refs/heads/main/illustrations/cpp/cpp_timeline.jpg) {.illustration} Начиная с версии C++11 можно говорить о зарождении **современного C++** (Modern C++). Это понятие включает в себя три аспекта: - Языковые средства. - Лучшие практики разработки. Они собраны в документе под названием [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) (CG). Мы будем ссылаться на рекомендации из CG на протяжении всего курса. - Актуальные версии компиляторов. Современный C++ позволяет создавать выразительный, масштабируемый и _безопасный_ код. В данном контексте под безопасностью понимается отсутствие ошибок управления памятью, способных открыть бреши для злоумышленников. К таким ошибкам относится переполнение буфера. Предположите, как будет называться следующий стандарт языка? {.task_text} Формат ответа: `C++NN`. {.task_text} ```consoleoutput {.task_source #cpp_chapter_0010_task_0030} ``` Стандарты выходят раз в 3 года. Последний стандарт называется C++23. {.task_hint} ```cpp {.task_answer} C++26 ``` ## Экосистема вокруг языка Свобода — один из столпов философии C++. Поэтому сам язык и его стандартная библиотека зафиксированы в стандарте языка, но все остальные инструменты разработчик выбирает сам. У C++ нет _стандартной_ системы автоматизации сборки, управления зависимостями, тестирования. Зато под каждую задачу найдется несколько проверенных временем альтернатив. ### Сборка Чтобы собрать проект на C++, нужен компилятор. И вот четыре самых популярных: - [GCC.](https://gcc.gnu.org/) По умолчанию установлен почти во всех десктоп-версиях дистрибутивов Linux. Разрабатывается в рамках [проекта GNU.](https://www.gnu.org/) - [Clang.](https://clang.llvm.org/) Кроссплатформенный компилятор семейства Си-подобных языков под зонтиком проекта [LLVM.](https://www.llvm.org/) - [Apple Clang.](https://opensource.apple.com/projects/llvm-clang/) Дистрибутив Clang для устройств Apple. - [MSVC.](https://visualstudio.microsoft.com/vs/features/cplusplus/) Компилятор от Microsoft, отлично подходящий для компиляции проектов под Windows. ![Лого компиляторов](https://raw.githubusercontent.com/senjun-team/senjun-courses/refs/heads/main/illustrations/cpp/cpp_compilers.png) {.illustration} Вместе с дебаггером и сопутствующими инструментами эти компиляторы входят в состав тулчейнов сборки. О них мы поговорим в одной из следующих глав. ### IDE и редакторы Выбор бесплатных кросс-платформенных сред для разработки на C++ довольно широкий. К сожалению, не все из них отличаются стабильностью и удобством. Есть две IDE, которые активно развиваются и позволяют комфортно работать с кодом: - [Visual Studio Code.](https://code.visualstudio.com/docs/languages/cpp) Для разработки на C++ нужно поставить [расширение.](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) - [Qt Creator.](https://doc.qt.io/qtcreator/creator-how-to-install.html) Довольно популярна платная кроссплафторменная IDE от JetBrains CLion. Многие пользователи приспосабливают для программирования на C++ свой любимый редактор: Sublime Text, Vim, Emacs, Atom. Для каждого из них найдутся плагины, упрощающие работу с кодом на C++. Выбор пользователей macOS зачастую падает на [Xcode.](https://developer.apple.com/xcode/) А под Windows практически единственным вариантом для коммерческой разработки является [Microsoft Visual Studio.](https://visualstudio.microsoft.com/) ### Библиотеки и фреймворки Стандартная библиотека C++ предоставляет контейнеры, алгоритмы, функции для работы с файловой системой, регулярными выражениями, датой/временем и многое другое. Тем не менее многого в ней не хватает. Например, C++ популярен для создания высоконагруженных сервисов. Но в стандартной библиотеке нет для этого _ни одного_ кирпичика! Веб-сервер, инструменты для работы с БД и очередями, веб-сокеты — все это привносится в проект через third party библиотеки. А некоторые компании предпочитают вести внутреннюю разработку всего этого добра. Вы удивлены? Такое положение дел может показаться недосмотром со стороны комитета по стандартизации C++. Но вспомните о том, что C++ предназначен для _эффективного_ решения широкого круга задач. Если бы в станадртной библиотеке и был веб-сервер, им бы почти никто не пользовался! Потому что нельзя спроектировать веб-сервер, который будет производителен для всех сценариев работы. И пользователи языка все равно обратятся к кастомизированным сторонним решениям. Так что если вы не отыщете в стандартной библиотеке средств для логирования, работы с сетевыми протоколами и форматами хранения данных, не удивляйтесь. Помните: на то есть причины. Часть потребностей перекрывает коллекция библиотек [boost.](https://www.boost.org/) [Boost.Asio](https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio.html) предназначен для кросс-платформенной работы с сетью, [Boost.Beast](https://www.boost.org/doc/libs/1_76_0/libs/beast/doc/html/index.html) реализует взаимодействие по HTTP и через веб-сокеты. В коллекции boost есть библиотеки на многие случаи жизни. Однако зачастую более специализированные решения оказываются эффективнее и современнее, чем boost. Вот краткий список библиотек для решения типовых задач: - Логирование: [spdlog.](https://github.com/gabime/spdlog) - Тестирование: [GoogleTest,](https://github.com/google/googletest) [Catch2,](https://github.com/catchorg/Catch2) [doctest.](https://github.com/doctest/doctest) - GUI: [Qt.](https://github.com/qt) - Веб-сервер: [restinio,](https://github.com/Stiffstream/restinio) [Crow,](https://github.com/CrowCpp/Crow) [userver.](https://github.com/userver-framework/userver) - Асинхронность: [libunifex.](https://github.com/facebookexperimental/libunifex) ### Линтеры, форматтеры и статические анализаторы кода Ни один серьезный проект на C++ не обходится без интеграции в CI/CD линтеров и статических анализаторов. Они не менее важны для выявления проблем, чем юнит-тесты. Вот два зарекомендовавших себя бесплатных инструмента: - Линтер [Clang-Tidy.](https://clang.llvm.org/extra/clang-tidy/) - Статический анализатор [Cppcheck.](https://cppcheck.sourceforge.io/) В мире C++ отсутствует единое руководство по правилам именования и оформления. Некоторые проекты вырабатывают свои конвенции, а некоторые — используют распространенные, например [Google Code Style.](https://google.github.io/styleguide/cppguide.html) Для форматирования кода в соответствии с выбранным стилем к проекту подключают форматтеры, чаще всего — [clang-format.](https://clang.llvm.org/docs/ClangFormat.html) ## Мифы о C++ Как сказал автор C++ Бьерн Страуструп, есть два типа языков программирования: те, которые ругают, и те, которые не используют. C++ — один из популярнейших языков в мире, и конечно же вокруг него много критики. Часть критики вполне обоснована, но часть порождена мифами вокруг языка. ### Мифический язык C/C++ C++ появился на свет как надстройка над Си. Долгое время он продолжал быть надмножеством Си. Кроме того, при развитии C++ особый упор делается на обратную совместимость. Если копнуть еще глубже, то по умолчанию все популярные компиляторы C++ собирают ваш проект таким образом, что к нему подключается стандартная библиотека Си. Однако Си не стоял на месте. Он давно перестал быть просто подмножеством C++. На данный момент Си и C++ — это **два разных языка.** В них практикуются зачастую _противоречащие друг другу_ подходы к обработке ошибок, управлению ресурсами, построению абстракций, организации кода. Подходы, которые хороши или даже единственно возможны в мире Си, расходятся с принципами Modern C++. Поэтому рекомендуем относиться к Си и C++ как к двум разным языкам, между которыми выстроено почти бесшовное взаимодействие. Оно реализовано через механизм, который называется интерфейсом внешних функций (FFI, Foreign Function Interface). FFI совмещает семантику и соглашения о вызове функций в Си и C++. ### C++ небезопасен Не такой уж и миф, если честно. На C++ действительно легко допустить ошибки, открывающие бреши в безопасности проекта. Как правило это ошибки использования памяти после освобождения, обращения к неправильной области памяти, двойного освобождения. Но риск этот сильно преувеличен, и на то есть причины: - Многие не разделяют Си и C++. И если на C++ применять практики, принятые в Си, вы получите небезопасный код. - В наши дни существует и здравствует огромное количество легаси на старом C++. В том числе это кодовые базы таких корпораций как Google, Microsoft, Apple. Эти проекты формировались во времена, когда в языке отсутствовали многие современные конструкции, а лучшие практики еще не были выработаны. К сожалению, проблемы этих проектов зачастую проецируются на современный C++. - Игнорирование современных возможностей языка. Термин «Modern C++» возник не просто так: начиная с C++11 в языке появилась масса средств для разработки безопасного, гибкого и читабельного кода. Чтобы свести риск возникновения опасных ошибок к минимуму, используйте в связке: - Modern C++. - Тесты. - Линтеры и статические анализаторы. Иногда, несмотря на все старания, в проект все же проникают трудно локализуемые ошибки. Их поиску и исправлению способствуют инструменты для: - Анализа памяти: [Valgrind](https://valgrind.org/) и [AddressSanitizer.](https://clang.llvm.org/docs/AddressSanitizer.html) - Обнаружения состояния гонки (data races) между потоками: [ThreadSanitizer.](https://clang.llvm.org/docs/ThreadSanitizer.html) - Поиска потенциально опасных конструкций: [UBSan.](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) ## Области применения C++ Есть категории задач, для решения которых C++ подходит прекрасно. Но есть и те, для которых C++ плох. C++ — удачный выбор для: - Разработки производительного обобщенного кода. Например, высоконагруженных сервисов, SDK, библиотек для сложных вычислений, пайплайнов обработки данных. - Низкоуровневых проектов: ОС, драйверов, микроконтроллеров, систем реального времени. - Таких ниш как программирование на [GPU,](https://ru.wikipedia.org/wiki/Графический_процессор) графический рендеринг, gamedev, [HFT](https://en.wikipedia.org/wiki/High-frequency_trading). А в этих случаях отдайте предпочтение языку попроще: - Быстрое прототипирование. Скорость разработки — не самое сильное качество C++. - Разработка продуктов, в которых _совершенно_ не важны производительность и экономия ресурсов. Использование в них C++ будет напоминать пальбу из пушки по воробьям. Для всех остальных задач C++ будет если не идеальным, то по крайней мере хорошим выбором. И наконец приведем краткий список знаменитых проектов на C++: - [Chromium](https://github.com/chromium/chromium) — браузер. - Базы данных [MongoDB](https://github.com/mongodb/mongo) и [ClickHouse.](https://github.com/ClickHouse/ClickHouse) - [V8](https://github.com/v8/v8) — движок JavaScript от Google. - [LibreOffice](https://www.libreoffice.org/about-us/source-code/) — офисный пакет. - Игровые движки [Unreal Engine](https://www.unrealengine.com) и [Unity.](https://unity.com/) - [Tensorflow](https://github.com/tensorflow/tensorflow) — библиотека для машинного обучения. - [React Native](https://github.com/facebook/react-native) — фреймворк для разработки мобильных и настольных приложений на JavaScript и TypeScript. - [LLVM](https://github.com/llvm/llvm-project) — инфраструктура для создания компиляторов. На базе LLVM построены компиляторы Rust, Swift, Kotlin, Julia и других популярных языков. Вы запомнили, как выглядит Hello World на C++23? Самостоятельно воспроизведите его. {.task_text} Вам помогут однострочные комментарии в коде. Они начинаются с двух слэшей: `//`. {.task_text} Если возникнут сложности, воспользуйтесь подсказкой. {.task_text} ```c++ {.task_source #cpp_chapter_0010_task_0040} // Импортируйте стандартную библиотеку. // Определите функцию main — точку входа в программу: // тип_возвращаемого_значения имя_функции() // { // тело функции // } // Внутри функции main вызовите функцию стандартной библиотеки // для печати в консоль строки "Hello World". // После импорта библиотеки и вызова функции не забудьте // поставить оператор ";". Уже в следующей главе вы узнаете, // для чего он нужен. ``` Модуль стандартной библиотеки называется `std`. Воспользуйтесь функцией `std::println()` из этого модуля. {.task_hint} ```c++ {.task_answer} import std; int main() { std::println("Hello World"); } ``` ## Домашнее задание 1. Установите на свой компьютер компилятор C++. Чем актуальнее версия — тем лучше. 2. Установите IDE или редактор кода, в котором вам будет комфортно работать. 3. Добейтесь компиляции и запуска Hello World в стиле C++17. Для компиляции Hello World в стиле C++23 потребуются дополнительные шаги, которые мы рассмотрим в следующих главах. - Сохраните программу в файл `main.cpp`. - Получите из исходного кода бинарный файл. Скомпилируйте файл из интерфейса IDE или из консоли. - Запустите исполняемый файл. Если вы все сделали правильно, то увидите строку "Hello World". ---------- ## Резюме - C++ предназначен для решения чрезвычайно широкого круга задач. - На C++ можно писать как низкоуровневый, так и высокоуровневый код. - C++ заточен под производительность и экономию ресурсов. - C++ — компилируемый язык со слабой статической типизацией. - В C++ есть абстракции с нулевым оверхедом и практикуется подход «не плати за то, что не используешь». - В C++ развито метапрограммирование на этапе компиляции. - Современный C++ (Modern C++) — это комбинация современных языковых средств, актуальных версий компиляторов и лучших практик по написанию выразительного и безопасного кода.
Отправка...
Наша группа в telegram. Здесь можно задавать вопросы и общаться.
Задонатить. Если вам нравится курс, вы можете поддержать развитие площадки!