C++ geek
3.73K subscribers
276 photos
4 videos
25 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
🔥11
✂️ C++17: Перестаньте копировать строки! (std::string_view)

Мы привыкли передавать строки в функции по константной ссылке: const std::string&. Нам кажется, что это эффективно, ведь мы не копируем объект, верно?

Не всегда. 🛑

Если вы передаете в такую функцию обычный текст в кавычках (строковый литерал) или часть другой строки, C++ втайне от вас создаст временный объект std::string, выделит память в куче (heap allocation), скопирует туда данные и только потом передаст ссылку.

Решение? std::string_view.

👀 Что это такое?
std::string_view - это супер-легкий объект, который ничего не хранит сам. Он просто «смотрит» на существующую строку. Внутри него только указатель на начало текста и длина.

Никаких аллокаций. Никаких копий. Ноль оверхеда.

🆚 Сравним:


// 🐢 ПЛОХО (до C++17)
void Log(const std::string& msg) { /* ... */ }

// При вызове создается временный std::string!
Log("Critical Error");




// 🚀 ХОРОШО (C++17)
void Log(std::string_view msg) { /* ... */ }

// Никаких аллокаций. Просто передаем указатель и длину.
Log("Critical Error");



🔥 Суперсила: Substrings без боли
Самое вкусное начинается, когда нужно взять подстроку.

⚫️std::string::substr() - создает новую строку (копирование + аллокация).
⚫️std::string_view::substr() - просто сдвигает указатель и меняет размер (математическая операция за наносекунды).

⚠️ Осторожно! (Подводный камень)
Так как string_view не владеет данными, а только смотрит на них, вы должны быть уверены, что исходная строка живет дольше, чем string_view.

⚫️ Использовать как аргумент функции.
⚫️ Возвращать из функции, если исходная строка была локальной переменной.

💡 Итог:
Если вам нужно только «почитать» строку (в аргументах функции), почти всегда используйте std::string_view вместо const std::string&.

#cpp #cpp17 #optimization #stringview #coding #tips

➡️ @cpp_geek
Please open Telegram to view this post
VIEW IN TELEGRAM
👍94
🏗 Тетрис в памяти: Почему порядок полей в классе важен?

Вы создали простую структуру: bool, int и еще один bool.
Математика проста: 1 байт + 4 байта + 1 байт = 6 байт.

Вы проверяете через sizeof и видите... 12 байт. 🤯
Куда делись еще 6 байт? Вы только что потеряли 50% памяти на "воздух".

Это называется Padding (Выравнивание).

⚙️ Как это работает?
Процессор не любит читать данные по произвольным адресам. Ему удобно читать кусками по 4 или 8 байт (слова). Чтобы int (4 байта) не "разломился" посередине двух слов, компилятор вставляет пустые байты-заглушки.

Плохой пример (Bad Layout):


struct Bad {
bool a; // 1 байт
// ... 3 байта PADDING (воздух) ...
int b; // 4 байта (должен начинаться с кратного 4 адреса)
bool c; // 1 байт
// ... 3 байта PADDING (чтобы выровнять общий размер) ...
};
// Итог: 12 байт



Хороший пример (Good Layout):

Просто меняем порядок полей. Правило: "От больших к маленьким".


struct Good {
int b; // 4 байта
bool a; // 1 байт
bool c; // 1 байт
// ... 2 байта PADDING (добиваем до кратности 4) ...
};
// Итог: 8 байт



📉 Почему это важно?
Кажется, что 4 байта ерунда. Но если у вас std::vector<Bad> на 1,000,000 элементов:

⚫️Bad: ~12 MB памяти.
⚫️Good: ~8 MB памяти.

Вы экономите 4 мегабайта просто переставив строчки местами! Плюс, более плотные данные лучше ложатся в кэш процессора (CPU Cache), что ускоряет обработку.

💡 Совет:
Объявляйте поля в порядке убывания их размера:

1. Указатели и double (8 байт)
2. int, float (4 байта)
3. short (2 байта)
4. bool, char (1 байт)

#cpp #optimization #memory #alignment #coding #tips

➡️ @cpp_geek
Please open Telegram to view this post
VIEW IN TELEGRAM
👍124💯1