C++ geek
3.61K subscribers
277 photos
5 videos
28 links
Учим C/C++ на примерах
Download Telegram
🚀 Микро-оптимизация в C++20: Early Return + Атрибуты вероятности

В прошлом посте мы разобрали, как Early Return (ранний возврат) спасает нас от вложенных if и делает код чище. Но в C++20 мы можем сделать этот код еще и потенциально быстрее!

Встречайте атрибуты [[likely]] и [[unlikely]].

🧠 В чем суть?
Современные процессоры пытаются предсказать, какую ветку кода программа выполнит следующей (Branch Prediction). Если процессор угадал - всё летает. Если ошибся - теряем такты на очистку конвейера.

С помощью атрибутов мы даем компилятору (и процессору) «инсайд»: какая ветка будет выполняться чаще.

🛠 Как это выглядит в коде?

Обычно ошибки и проверки аргументов (Guard Clauses) срабатывают редко. Это идеальное место для [[unlikely]].


void ProcessImage(Image* img) {
// 1. Проверка на null.
// Это случается редко, помечаем как "маловероятно".
if (img == nullptr) [[unlikely]] {
return; // Компилятор уведет этот код "подальше" из горячего пути
}

// 2. Еще одна проверка
if (img->IsEmpty()) [[unlikely]] {
return;
}

// --- Happy Path ---
// Процессор сразу прыгнет сюда, ожидая, что проверки выше ложны.
img->ApplyFilter();
img->Save();
}



⚙️ Что происходит под капотом?
Компилятор переставит инструкции ассемблера так, чтобы «счастливый путь» шел линейно, без прыжков (jmp), что улучшает работу кэша инструкций. Код обработки ошибок (ветка [[unlikely]]) будет сдвинут в конец функции или в «холодную» зону.

⚠️ Важный нюанс:
Используйте это только тогда, когда вы уверены в вероятностях (например, ошибки случаются в 1 случае из 1000). Если поставить атрибуты наугад, можно сделать только хуже (pessimization).

🔥 Итог:
Чистый код (Early Return) + Подсказки компилятору ([[unlikely]]) = Читаемость и Производительность.

#cpp #cpp20 #coding #optimization #tips #programming

➡️ @cpp_geek
🔥12
🌉 Забудьте про передачу указателей и размеров! (std::span)

Помните, мы обсуждали std::string_view - легковесное «окно» для строк? В C++20 у него появился старший брат для массивов и векторов - std::span.

До C++20 у нас была классическая проблема. Допустим, вы пишете функцию, которая должна обработать список чисел.

🐢 Как мы писали раньше:

Вариант 1: Принимать const std::vector<int>&.
Минус: Функция теперь намертво привязана к std::vector. Если у вас данные лежат в std::array или обычном си-массиве int arr[10], придется копировать их в вектор. Аллокации, тормоза.

Вариант 2: Си-стайл (Указатель + размер).
Минус: Легко ошибиться с размером, потерять контекст, код выглядит грязно.


void ProcessOld(const int* data, size_t size) { /* ... */ }



🚀 Как мы пишем теперь (C++20):


#include <span>

// Принимаем любой непрерывный кусок памяти!
void ProcessNew(std::span<const int> data) {
for (int val : data) {
std::cout << val << " ";
}
}



👀 Что такое std::span?
Как и string_view, это просто указатель на начало данных и их длина (обычно 16 байт). Он не владеет памятью, он только на нее смотрит.

Магия в том, что std::span умеет автоматически создаваться из чего угодно:


std::vector<int> vec = {1, 2, 3};
std::array<int, 3> arr = {4, 5, 6};
int raw[3] = {7, 8, 9};

// Одна функция работает со всеми типами контейнеров! Без копирования!
ProcessNew(vec);
ProcessNew(arr);
ProcessNew(raw);



✂️ Суперсила: Subspan (Подмассивы)
Вам нужно передать в функцию только часть вектора, например, со 2-го по 5-й элемент? Никаких итераторов и копирования:


// Передаем кусок вектора за O(1)
ProcessNew( std::span{vec}.subspan(1, 4) );



⚠️ Важный нюанс:
std::span не умеет изменять размер данных (никаких push_back). Но он может изменять сами элементы, если вы передадите std::span<int> (без const).

💡 Итог: Если ваша функция принимает набор данных только для чтения или изменения элементов на месте, всегда используйте std::span. Это золотой стандарт современного C++.

#cpp #cpp20 #stdspan #optimization #memory #coding #tips

➡️ @cpp_geek
👍10🔥32
C++: Заставьте компилятор работать за вас (constexpr и consteval)

Вы когда-нибудь хотели, чтобы ваша программа мгновенно выдавала результат сложных вычислений в момент запуска? Это возможно, если переложить тяжелую математику на... ваш компилятор!

В современном C++ мы можем «запекать» результаты функций прямо в итоговый .exe файл. Для этого есть два инструмента.

1. constexpr - «Вычисли до запуска, если сможешь» (C++11)

Ключевое слово constexpr говорит компилятору: "Если все аргументы этой функции известны заранее, вычисли её прямо сейчас. Если нет - оставь до выполнения программы (Run-time)".

Это невероятно удобно для универсальных функций.


// Функция может работать и до запуска, и во время!
constexpr int GetArea(int width, int height) {
return width * height;
}

int main() {
// 🚀 Вычислится компилятором! В код вставится просто "200".
// Zero runtime cost.
int a = GetArea(10, 20);

int w;
std::cin >> w;
// 🐢 Вычислится процессором во время работы (w неизвестно заранее).
int b = GetArea(w, 20);
}



2. consteval - «Вычисли до запуска, или умри!» (C++20)

У constexpr есть проблема: мы не всегда уверены, вычислилась ли функция компилятором, или она тихо «соскользнула» в Run-time, замедляя программу.

Поэтому в C++20 добавили consteval. Это строгий приказ (Immediate Function). Если компилятор не может выполнить функцию прямо сейчас - он выдаст ошибку компиляции.


// Обязана выполниться во время компиляции
consteval int MagicHash(std::string_view str) {
int hash = 0;
for (char c : str) hash += c;
return hash;
}

int main() {
// Отлично. Компилятор сам посчитает хэш слова "admin".
int h1 = MagicHash("admin");

std::string user_input = "test";
// ОШИБКА КОМПИЛЯЦИИ! user_input нельзя знать заранее.
int h2 = MagicHash(user_input);
}



📈 Зачем это нужно?

1. Максимальная производительность: Вы переносите время выполнения на этап сборки программы. Для пользователя всё работает за O(1).

2. Замена #define: Раньше константы и простые формулы писали через макросы препроцессора. Теперь constexpr делает это безопасно, с проверкой типов.

3. Безопасность: С consteval вы гарантируете, что тяжелая инициализация (например, генерация таблиц поиска) не ударит по производительности в продакшене.

💡Итог: Пишете математику или чистые функции без побочных эффектов? Ставьте constexpr.
Хотите 100% гарантию, что вычисления не попадут в готовый бинарник? Ставьте consteval.

#cpp #cpp20 #constexpr #optimization #performance #coding #tips

➡️ @cpp_geek
👍53