Программирование и IT
Си плюс плюс (C++) с нуля
Си плюс плюс — компилируемый язык, на котором пишут там, где важны скорость и прямой доступ к памяти: движки игр, браузеры, базы данных, прошивки. Порог входа выше, чем у Python, но первая работающая программа собирается в первый же вечер.
В этой статье
Что это за язык#
C++ вырос из языка C в начале 1980-х: Бьёрн Страуструп добавил к нему классы,
а потом и остальное, чем язык известен сегодня. Название читается «си плюс
плюс», а два плюса — это шутка авторов: в языке C оператор ++ увеличивает
значение на единицу.
Главное отличие от Python и JavaScript — компиляция. Исходный текст заранее
переводится в машинные инструкции, и получается самостоятельный файл, которому
для запуска не нужен ни интерпретатор, ни виртуальная машина. Отсюда скорость,
отсюда же и строгость: об ошибке в типах ты узнаёшь при сборке, а не во время
работы программы у пользователя.
Второе отличие — память под твоим управлением. Язык не решает за тебя, когда
освобождать занятое. Это даёт контроль над каждым байтом и одновременно
создаёт целый класс ошибок, которых в других языках просто нет.
Язык развивается редакциями стандарта: C++11, C++14, C++17, C++20, C++23.
Современный код на си плюс плюс сильно отличается от учебников девяностых —
ручное выделение памяти, указатели на каждом шагу и массивы в стиле C уступили
место контейнерам и умным указателям. Если в пособии первая же программа
начинается с #include <stdio.h> и void main(), оно устарело.
Где он применяется#
- Игры. Unreal Engine написан на си плюс плюс, и логика игр в нём — тоже.
- Браузеры и операционные системы. Движки отрисовки страниц, ядра систем,
драйверы. - Базы данных и высоконагруженные сервисы. Там, где миллисекунда стоит
денег. - Встраиваемая техника. Микроконтроллеры, станки, автомобильная
электроника. Соседний вход в ту же область — Arduino для
начинающих: там применяется
упрощённый C++ и результат сразу виден на плате. - Инженерные и графические пакеты. САПР, обработка изображений, звук и
видео.
Чего на этом языке обычно не делают: простые сайты, скрипты-однодневки,
аналитику данных. Там выигрывают языки, где меньше ручной работы.
Что поставить#
Нужны две вещи: компилятор и редактор.
Компилятор. В Linux почти всегда уже стоит GCC, иначе он ставится пакетным
менеджером (sudo apt install build-essential). В macOS его роль играет Clang
из Command Line Tools — xcode-select --install. В Windows два пути: Visual
Studio Community с набором «Разработка на C++» или MinGW-w64 с компилятором
GCC.
Редактор. Visual Studio Code с официальным расширением C/C++ — бесплатный
и достаточный вариант на любой системе. Visual Studio Community — сильная
бесплатная среда под Windows. CLion удобен, но платный.
Проверить, что всё на месте:
Если версия напечаталась — компилятор найден и можно писать код. Работа в
терминале здесь не прихоть, а обычный режим: команды сборки и запуска
набираются руками, а базовый набор команд разобран в
шпаргалке по Linux.
Первая программа#
Создай файл hello.cpp:
int
Что здесь происходит. #include <iostream> подключает средства ввода-вывода.
int main() — функция, с которой начинается выполнение: она обязана быть ровно
одна на всю программу. std::cout — поток вывода, << отправляет в него
значение, std::endl переводит строку. return 0 сообщает системе, что
программа завершилась без ошибок.
Собери и запусти:
Ключ -o hello задаёт имя готовой программы (в Windows — hello.exe); без
него получится файл a.out. Ключи -Wall -Wextra включают предупреждения —
ставь их с первого дня, компилятор заметит половину твоих ошибок раньше тебя.
-std=c++17 фиксирует редакцию стандарта.
Следующий шаг — ввод и переменные:
int
Как из текста получается программа#
Сборка идёт в несколько шагов, и знание их названий экономит часы на разборе
ошибок.
- Препроцессор подставляет содержимое заголовков вместо строк
#include. - Компилятор переводит каждый файл
.cppв объектный файл. - Компоновщик сшивает объектные файлы и библиотеки в готовую программу.
Отсюда два разных сорта ошибок. Ошибка компиляции звучит как «expected ';'» или
«no matching function» — проблема в тексте одного файла. Ошибка компоновки —
«undefined reference to …» — текст в порядке, но реализации функции нет ни в
одном файле, или забыли подключить библиотеку.
Когда файлов становится больше трёх, команды сборки записывают в CMake — и
дальше одна и та же конфигурация собирается на любой системе.
Память и указатели без страшных слов#
Переменная живёт по какому-то адресу. Указатель — переменная, которая хранит
этот адрес.
int x = 5;
int* p = &x; // p хранит адрес x
*p = 8; // записать по адресу — то же, что записать в x
std::cout << x; // 8
Знак & перед именем берёт адрес, звёздочка перед указателем — обращается к
значению по адресу. Ссылка проще: int& r = x; — это второе имя той же
переменной, её нельзя оставить пустой и нельзя перенаправить.
Память бывает двух сортов. Переменные внутри функции лежат на стеке и
уничтожаются сами при выходе из блока. Объекты, созданные через new, лежат в
куче и живут, пока их не удалят.
int* data = new int;
// ... работа ...
delete[] data; // забыли — утечка памяти
Именно в этой паре — источник трёх классических бед: утечка (забыли delete),
двойное освобождение (удалили дважды) и висячий указатель (обратились после
удаления). Современный ответ на все три — не писать new руками:
std::vector<int> numbers = ;
numbers.; // размер стал 4
auto ptr = std::make_unique<int>; // освободится само
std::vector сам выделяет и отдаёт память, std::unique_ptr освобождает
объект, когда выходит из области видимости. Принцип, на котором это держится,
называется RAII: владение ресурсом привязано к времени жизни объекта. Его
стоит понять раньше, чем классы, — он объясняет, почему в аккуратном коде на
си плюс плюс почти не встречается ручного освобождения.
План изучения#
Сроки ниже — ориентир при занятиях по часу в день, а не обещание.
Первый месяц уходит на основы: типы, условия, циклы, функции, массивы и
std::vector, std::string. Критерий готовности — двадцать решённых задач без
подсказок: обработка чисел, строки, простая статистика по массиву.
Второй месяц — структуры и классы: поля, методы, конструктор и деструктор,
разделение на заголовок .h и реализацию .cpp. Здесь же — сборка проекта из
нескольких файлов.
Третий месяц — память и то, что вокруг: указатели, ссылки, передача аргументов
по значению и по ссылке, умные указатели, RAII. Хороший признак усвоения —
умение объяснить, почему копирование большого объекта в аргументе функции
дорого.
Дальше — стандартная библиотека (контейнеры, алгоритмы, итераторы), шаблоны,
а затем выбор направления: движок игры, встраиваемая техника, серверная
разработка. Единого «полного знания» языка не существует, и это нормально.
Частые ошибки новичка#
Указатель без инициализации. int* p; содержит мусор, а запись по нему
роняет программу в случайном месте. Всегда присваивай адрес или nullptr.
Выход за границу массива. У вектора из десяти элементов последний индекс —
девять. Компилятор об этом не предупредит, программа может даже не упасть — и
испортит соседние данные.
= вместо == в условии. if (x = 5) присвоит пятёрку и всегда окажется
истиной. Ключ -Wall про это предупреждает.
Учебник из прошлого века. Код с #include <iostream.h>, void main() и
gets() не соберётся современным компилятором или соберётся с дырами.
Отлаживать удобнее не печатью значений, а отладчиком: g++ -g добавляет
отладочную информацию, дальше gdb ./hello останавливает программу в нужной
строке и показывает значения переменных.
План по этапам
- Собрать первую программуПоставить компилятор, написать hello.cpp и собрать его с ключами -Wall -Wextra.
- Основы языкаРешить двадцать задач на условия, циклы, функции и вектор — без подсказок и готовых решений.
- Свои типыОписать класс с конструктором и деструктором, разнести объявление и реализацию по двум файлам.
- ПамятьРазобрать указатели и ссылки, переписать пример с new/delete на std::vector и unique_ptr.
- Проект из нескольких файловСобрать программу на 300–500 строк через CMake и запустить её на другой машине.
Начать изучать эту тему у себя
План ляжет в твой репозиторий: отмечай этапы, веди конспект — история изменений покажет, как ты продвинулся.
Проверь себя
1.Чему равно x после кода: int x = 5; int* p = &x; *p = *p + 3;
2.Какой ключ g++ задаёт имя готовой программы?
3.С какой функции начинается выполнение программы на C++?
4.Чему равен size() вектора после кода: std::vector<int> v = {1, 2, 3}; v.push_back(4);
Источники
-
cppreferenceПолный справочник по языку и стандартной библиотекебесплатно
-
isocpp.orgСайт комитета по стандарту: руководство по современному стилю и ответы на частые вопросыбесплатно
-
Документация GCCКлючи компилятора и расшифровка предупрежденийбесплатно
-
StepikБесплатные курсы с автопроверкой решенийбесплатно
Было полезно?