Від Python до C++: Чому розрив здається таким великим
Практичний погляд на те, чому перехід від Python до C++ створює труднощі, і на чому варто зосередити увагу під час його вивчення.
Кожний програміст Python, який вперше торкається C++, має ту саму реакцію: чому для виведення "hello world" потрібна вся ця церемонія? Стрибок — це не просто синтаксис. Це зміна в тому, як вас очікують думати про пам'ять, типи та те, що комп'ютер насправді робить під час виконання вашої програми.
Що Python для вас приховував
Python працює на інтерпретаторі (найчастіше CPython), який обробляє розподіл пам'яті, збирання сміття та перевірку типів за сценами. Коли ви пишете x = 5, а потім x = "hello", Python просто переприсвоює ім'я. Ніяких скарг, ніяких очисток з вашої сторони.
C++ цього для вас не робить. Коли ви пишете int x = 5;, ви зарезервували фіксований блок пам'яті розміром під ціле число. Ви не можете потім вставити в нього рядок. І коли ви динамічно виділяєте пам'ять за допомогою new, ви несете відповідальність за її звільнення за допомогою delete — якщо забудете, у вас буде витік пам'яті. Забудете перевірити, чи є вказівник null перед його розіменуванням, — у вас буде segfault. Python жертвує продуктивністю заради мереж безпеки. C++ дає вам ножиці й довіряє вам не бігти з ними.
Статичне типізування змінює те, як ви пишете код, не лише те, як ви оголошуєте змінні
У Python сигнатури функцій — це пропозиції. У C++ це контракти, що примушуються під час компіляції:
int add(int a, int b) {
return a + b;
}
Певні add(3, "four") — і компілятор зупиняє вас до того, як програма коли-небудь запуститься. Python щасливо дозволяв би вам написати def add(a, b): return a + b, а потім упасти під час виконання в момент, коли хтось передасть в нього несумісні типи. Це не невелике незручність — це інша філософія щодо того, коли помилки повинні появитися. C++ хоче, щоб ви ловили баги під час компіляції. Python задоволений ловити їх у production, якщо ви не написали тести.
Управління пам'яттю — це справжня навчальна програма
Найбільший концептуальний стрибок — це розуміння stack проти heap. Локальні змінні та параметри функцій звичайно живуть у stack, і вони чистять себе автоматично, коли функція повертається. Все, що створено за допомогою new, живе на heap, і там залишається, поки ви явно не видалите його за допомогою delete або не обгорнете його у смарт-вказівник.
Сучасний C++ (C++11 та пізніше) дає вам std::unique_ptr та std::shared_ptr саме тому, щоб ви не мали управляти сирими вказівниками так часто:
std::unique_ptr<int> ptr = std::make_unique<int>(42);
Цей об'єкт знищує себе, коли виходить із области видимості — ніякого ручного delete не потрібно. Якщо ви вивчаєте C++ у 2024, переходьте одразу до смарт-вказівників і RAII (Resource Acquisition Is Initialization) паттернів замість того, щоб грома через вправи з арифметикою сирих вказівників, призначені для програми 1998 року. Вам все одно потрібно концептуально розуміти вказівники, але вам не потрібно писати код malloc/free, щоб це доказати.
Компіляція — це інший цикл зворотного зв'язку
Python дає вам миттєвий зворотний зв'язок: запустіть скрипт, побачите помилку, виправте її, запустіть знову. C++ вставляє крок компіляції між ними, і цей крок ловить всю категорію багів, яку Python відкладає на час виконання. Компіляція з g++ -Wall -Wextra program.cpp -o program та звернення уваги на кожне попередження заощадить вам годин плутаної відладки пізніше. Невідповідності типів, неініціалізовані змінні та проблеми порівняння signed/unsigned все з'являються тут замість таємничої поведінки під час виконання. Компромісом є швидкість ітерації: ваш цикл edit-compile-run повільніший за Python edit-run, особливо на більших кодбейсах, де повна перебудова може тривати хвилини. Саме тому такі інструменти як ccache та інкрементальні збірки через CMake мають значення, коли ваші проекти виростають далі за кілька файлів.
Де це насправді має значення на практиці
Ви не вивчаєте C++, щоб писати ті ж програми, які ви писали на Python, швидше. Ви вивчаєте його, тому що деякі проблеми його потребують: ігрові движки зі строгими бюджетами кадрів, вбудовані системи з кількома кілобайтами ОЗУ, системи торгівлі з високою частотою, де мікросекунди коштують грошей, або компоненти операційної системи, які лежать під самим інтерпретатором Python. Якщо ви займаєтесь безпекою, розуміння моделі пам'яті C++ також безпосередньо пояснює, як буферні переповнення та вразливості use-after-free відбуваються на двійковому рівні — знання, яке абстракції Python активно приховують від вас.
Чесна порада: не намагайтесь зробити C++ схожим на Python. Дозвольте йому деякий час бути незручним. Незручність — це сенс. Вона навчає вас тому, що ваш інтерпретатор Python робив для вас весь цей час.
Якщо цей вид мовного порівняння корисний, Korra Studio має пов'язані сегменти про безпеку пам'яті, основи системного програмування та зворотне проектування, які будуються саме на цих концепціях.
Написано з допомогою штучного інтелекту, перевірено та опубліковано Мішалем Пільчем (CISSP), Korra Studio.
Це одна замітка з бази знань Korra Studio — платформа поєднує кожну тему з 1-на-1 менторингом.
Початок безплатноarrow_forward