Собираем ring buffer на C++!
Нужно хранить только последние N значений. Когда буфер заполнен, новое значение должно вытеснять самое старое.
В этой задаче:
Такой приём полезен для метрик, логов, истории последних событий и небольших очередей фиксированного размера.
📣 C++ Ready | #задача
Нужно хранить только последние N значений. Когда буфер заполнен, новое значение должно вытеснять самое старое.
В этой задаче:
• держим данные в std::array
• считаем позицию через остаток от деления
• не двигаем элементы вручную
Такой приём полезен для метрик, логов, истории последних событий и небольших очередей фиксированного размера.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2🔥1
Почему из map нельзя удалять элементы как попало во время обхода?
Иногда нужно пройтись по контейнеру и удалить часть элементов. Например, убрать просроченные сессии, пустые записи, старые токены или временные ключи после фоновой очистки.
На первый взгляд хочется написать обычный цикл.
Выглядит логично. Мы стоим на элементе, проверяем его и удаляем, если он больше не нужен.
Но после erase(it) итератор it становится невалидным. А в конце итерации цикл всё равно попробует выполнить ++it.
То есть программа двигает уже сломанный итератор. Такое поведение может проявиться не сразу, а только на некоторых данных или сборках.
Правильный паттерн такой.
erase возвращает итератор на следующий элемент. Поэтому после удаления мы не делаем ++it вручную, а сразу продолжаем обход с корректной позиции.
Если элемент не удалили, тогда обычный ++it нужен. Именно поэтому инкремент убирают из заголовка for.
Для std::map и std::unordered_map это особенно важно, когда очистка идёт по условию внутри цикла.
Если нужно просто удалить всё по предикату и у вас C++20, можно использовать std::erase_if.
Но явный цикл всё равно полезно знать. Он нужен, когда вместе с удалением нужно логировать, считать статистику или выполнять дополнительное действие.
Главная мысль простая. Если удаляешь элемент через итератор во время обхода, следующий итератор должен прийти из erase, а не из ++ после удаления.
Есть ещё одна частая ошибка. Иногда удаление пытаются спрятать внутрь range-for.
Так делать не стоит.
Range-for сам управляет итератором внутри цикла. Если контейнер меняется во время обхода, этот внутренний итератор тоже может стать невалидным.
Поэтому для удаления по условию лучше сразу писать явный итераторный цикл. Он чуть длиннее, зато в нём видно, где именно происходит переход к следующему элементу.
Если внутри удаления есть дополнительные действия, их тоже удобно держать рядом.
Такой код проще читать при ревью. Видно и условие удаления, и побочный эффект, и безопасное обновление итератора.
📣 C++ Ready | #совет
Иногда нужно пройтись по контейнеру и удалить часть элементов. Например, убрать просроченные сессии, пустые записи, старые токены или временные ключи после фоновой очистки.
На первый взгляд хочется написать обычный цикл.
for (auto it = cache.begin(); it != cache.end(); ++it) {
if (it->second.expired()) cache.erase(it);
}Выглядит логично. Мы стоим на элементе, проверяем его и удаляем, если он больше не нужен.
Но после erase(it) итератор it становится невалидным. А в конце итерации цикл всё равно попробует выполнить ++it.
То есть программа двигает уже сломанный итератор. Такое поведение может проявиться не сразу, а только на некоторых данных или сборках.
Правильный паттерн такой.
for (auto it = cache.begin(); it != cache.end(); ) {
if (it->second.expired()) {
it = cache.erase(it);
} else {
++it;
}
}erase возвращает итератор на следующий элемент. Поэтому после удаления мы не делаем ++it вручную, а сразу продолжаем обход с корректной позиции.
Если элемент не удалили, тогда обычный ++it нужен. Именно поэтому инкремент убирают из заголовка for.
Для std::map и std::unordered_map это особенно важно, когда очистка идёт по условию внутри цикла.
Если нужно просто удалить всё по предикату и у вас C++20, можно использовать std::erase_if.
std::erase_if(cache, [](const auto& item) {
return item.second.expired();
});Но явный цикл всё равно полезно знать. Он нужен, когда вместе с удалением нужно логировать, считать статистику или выполнять дополнительное действие.
Главная мысль простая. Если удаляешь элемент через итератор во время обхода, следующий итератор должен прийти из erase, а не из ++ после удаления.
Есть ещё одна частая ошибка. Иногда удаление пытаются спрятать внутрь range-for.
Так делать не стоит.
for (auto& [key, value] : cache) {
if (value.expired()) cache.erase(key);
}Range-for сам управляет итератором внутри цикла. Если контейнер меняется во время обхода, этот внутренний итератор тоже может стать невалидным.
Поэтому для удаления по условию лучше сразу писать явный итераторный цикл. Он чуть длиннее, зато в нём видно, где именно происходит переход к следующему элементу.
Если внутри удаления есть дополнительные действия, их тоже удобно держать рядом.
if (it->second.expired()) {
log_removed(it->first);
it = cache.erase(it);
}Такой код проще читать при ревью. Видно и условие удаления, и побочный эффект, и безопасное обновление итератора.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤4🔥2
Интересный разбор архитектуры сцен в графических движках!
В статье автор разбирает, почему классический Scene Graph не всегда хорошо ложится на современные render pipeline, explicit API и задачи с большим количеством объектов.
В статье автор показывает:
• почему древовидная сцена может мешать производительности
• как думать о данных, зависимостях и проходах рендера
• почему современному движку часто нужен более гибкий подход
📣 C++ Ready | #статья
В статье автор разбирает, почему классический Scene Graph не всегда хорошо ложится на современные render pipeline, explicit API и задачи с большим количеством объектов.
В статье автор показывает:
• почему древовидная сцена может мешать производительности
• как думать о данных, зависимостях и проходах рендера
• почему современному движку часто нужен более гибкий подход
Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍5🔥4
Полезная статья про автоматическую проверку архитектуры C++-проекта!
Автор разбирает инструмент archcheck, который помогает описать правила зависимостей между модулями и проверять, что кодовая база не превращается в хаотичный клубок include-связей.
В статье автор показывает:
• как описывать допустимые зависимости между частями проекта
• как находить нарушения архитектурных границ
• почему такие проверки полезно запускать в CI
📣 C++ Ready | #статья
Автор разбирает инструмент archcheck, который помогает описать правила зависимостей между модулями и проверять, что кодовая база не превращается в хаотичный клубок include-связей.
В статье автор показывает:
• как описывать допустимые зависимости между частями проекта
• как находить нарушения архитектурных границ
• почему такие проверки полезно запускать в CI
Продолжай читать на Habr
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤4🔥4😁1
This media is not supported in your browser
VIEW IN TELEGRAM
Очнись, нас готовят к цифровому ГУЛАГу
Уже в десятках регионов России отключают мобильный интернет (даже когда нет атак БПЛА), тестируют «белые списки» и замедляют Телегу.
90% людей тупо смотрят на уплывающий корабль свободного Интернета. Люди поумнее готовятся к новой реальности и читают «Пакет Безопасности».
Здесь дают самые свежие связки для приватности: приложения и утилиты на случай вайтлистов, прокси, браузеры, сервисы — чего тут только нет.
Без шуток, сейчас это один из самых полезных каналов в Телеге. Надеемся на лучшее, но к чему нужно готовиться — вы и сами понимаете: @package_security
Уже в десятках регионов России отключают мобильный интернет (даже когда нет атак БПЛА), тестируют «белые списки» и замедляют Телегу.
90% людей тупо смотрят на уплывающий корабль свободного Интернета. Люди поумнее готовятся к новой реальности и читают «Пакет Безопасности».
Здесь дают самые свежие связки для приватности: приложения и утилиты на случай вайтлистов, прокси, браузеры, сервисы — чего тут только нет.
Без шуток, сейчас это один из самых полезных каналов в Телеге. Надеемся на лучшее, но к чему нужно готовиться — вы и сами понимаете: @package_security
😁8👎7👍1
Считаем размер папки через std::filesystem!
Иногда нужно быстро понять, сколько места занимает директория. Например, перед очисткой, анализом или проверкой файлов.
В C++17 для обхода файловой системы есть
Подключим нужные заголовки:
Для удобства заведём namespace:
Функция будет принимать путь к папке:
Сначала заведём счётчик байт:
Теперь рекурсивно обойдём директорию:
Нас интересуют только обычные файлы. Папки и ссылки можно пропустить:
Размер файла добавляем в общий счётчик:
После обхода возвращаем результат:
Вызов может выглядеть так:
В реальном коде стоит помнить про права доступа. Если часть файлов нельзя прочитать, можно использовать перегрузки с
📣 C++ Ready | #практика
Иногда нужно быстро понять, сколько места занимает директория. Например, перед очисткой, анализом или проверкой файлов.
В C++17 для обхода файловой системы есть
std::filesystem.Подключим нужные заголовки:
#include <filesystem>
#include <iostream>
Для удобства заведём namespace:
namespace fs = std::filesystem;
Функция будет принимать путь к папке:
std::uintmax_t dir_size(const fs::path& root) {Сначала заведём счётчик байт:
std::uintmax_t total = 0;
Теперь рекурсивно обойдём директорию:
for (const auto& entry : fs::recursive_directory_iterator(root)) {Нас интересуют только обычные файлы. Папки и ссылки можно пропустить:
if (!entry.is_regular_file()) continue;
Размер файла добавляем в общий счётчик:
total += entry.file_size();
После обхода возвращаем результат:
return total;
}
Вызов может выглядеть так:
auto bytes = dir_size("logs");
std::cout << bytes << "\n";В реальном коде стоит помнить про права доступа. Если часть файлов нельзя прочитать, можно использовать перегрузки с
std::error_code, чтобы программа не падала на первом недоступном каталоге.Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍5🔥3