C/C++ Ready | Программирование
16.1K subscribers
1.53K photos
94 videos
764 links
Авторский канал по разработке на C и C++.
Ресурсы, гайды, задачи, шпаргалки.
Информация ежедневно пополняется!

Cотрудничество: @energy_c

Реклама на бирже: https://telega.in/channels/cpp_ready/card

РКН: https://clck.ru/3QREHc
Download Telegram
Знали, что ключ в std::map можно переименовать без пересоздания узла?

Ключи внутри map нельзя менять напрямую, потому что контейнер поддерживает порядок элементов. Начиная с C++17 элемент можно временно извлечь как node handle, изменить его ключ и вставить обратно без копирования хранимого значения.

Сначала извлекаем элемент и проверяем, что он найден:
auto node = users.extract(oldKey);
if (node.empty()) return;


Пустой node handle означает, что такого ключа в контейнере не было. Пока узел извлечён, он не участвует в сортировке map, поэтому ключ можно изменить:
auto oldKey = node.key();
node.key() = newKey;


Сам объект и его mapped value остаются внутри узла. Это полезно, когда значение дорого копировать или оно не копируется вовсе:
auto& profile = node.mapped();
profile.lastSeen = now;


Теперь пробуем вернуть узел и проверяем результат, потому что newKey мог уже появиться в map:
auto result = users.insert(std::move(node));
if (result.inserted) {
    std::cout << "renamed\n";
}


При конфликте запись не теряется, она остаётся в result.node. Можно восстановить старый ключ и вернуть её в контейнер:
if (!result.inserted) {
    result.node.key() = oldKey;
    users.insert(std::move(result.node));
}


Успешная вставка возвращает тот же узел без пересоздания значения. Такой приём удобен для переименования ключей, если важно сохранить объект и явно обработать возможный конфликт.

📣 C++ Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍4🔥2
Синхронизируем потоки через примитивы C++20!

В этой шпоре собраны три разных сценария координации потоков. latch ждёт однократную готовность, barrier собирает участников на каждой фазе, а counting_semaphore ограничивает параллельный доступ к ресурсу.

📣 C++ Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12❤4👍3
Please open Telegram to view this post
VIEW IN TELEGRAM
😁6👎4
Почему компаратор с <= может сломать std::sort?

При сортировке чисел по возрастанию хочется написать сравнение так:
std::sort(values.begin(), values.end(),
[](int a, int b) { return a <= b; });


Проблема проявляется, когда в диапазоне есть одинаковые значения. Для двух равных чисел компаратор возвращает true, хотя ни одно из них не должно стоять раньше другого.

Проверим самую простую ситуацию:
auto lessOrEqual = [](int a, int b) { return a <= b; };
std::cout << lessOrEqual(5, 5);


Результат равен 1. Но std::sort требует строгий слабый порядок, элемент не может быть меньше самого себя. Использование такого компаратора нарушает требования алгоритма.

Правильный вариант для возрастания использует строгое сравнение:
std::sort(values.begin(), values.end(),
[](int a, int b) { return a < b; });


Если у объектов несколько полей, добавь запасной критерий. Например, при одинаковом приоритете можно сравнить id:
if (a.priority != b.priority) return a.priority < b.priority;
return a.id < b.id;


Так порядок будет предсказуемым и для равных приоритетов. Если же требуется сохранить исходный порядок равных элементов, используй std::stable_sort с корректным строгим компаратором, а не заменяй < на <=.

📣 C++ Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍3🔥2
Собираем конфигурацию с приоритетом источников на C++!

Настройки могут приходить из файла, переменных окружения и аргументов запуска. Соберём единый конфиг и сохраним источник каждого итогового значения.

В этой задаче:
• описываем слой настроек и его источник
• применяем слои от низкого приоритета к высокому
• сохраняем источник последнего значения


Так конфигурацию можно не только собрать, но и понять, какой источник переопределил параметр.

📣 C++ Ready | #задача
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤4🔥3
Gemini Pro на 24 месяца за 800₽!

Вместо 39.000₽ — всего 800₽ ($9.9) за 2 года. По акции сейчас это 33₽ в месяц, в 48 раз выгоднее!

➡Argon 4.0 + Claude Opus 5.5 — для кода
➡Nano Banana 2 Pro — для картинок
➡Генерация видео — ролики и анимации
➡AntiGravity + 5 ТБ облака
➡Opus 5.5 и Sonnet 5.5
➡Youtube Premium

Акция ограничена по времени, дальше будет официальная цена 480$!


Приобрести можно в Магазине с 20.000+ покупок и 2000+ отзывов (есть возвраты и замены).
Please open Telegram to view this post
VIEW IN TELEGRAM
👎10❤2👍1😁1
Объединяем две хронологии событий без повторной сортировки!

Представим, что приложение получило события из двух источников. Каждый источник уже отсортировал свои записи по времени. Чтобы получить общую хронологию, не нужно складывать всё вместе и сортировать заново, два упорядоченных диапазона можно слить.

Опишем событие и подготовим два входных списка. Внутри каждого время должно идти по возрастанию:
struct Event {
int time;
std::string message;
};

std::vector<Event> app = {{10, "start"}, {30, "save"}};
std::vector<Event> worker = {{20, "job"}, {40, "done"}};


Заранее выделим место под все записи. Это не меняет размер вектора, но избавляет его от лишнего расширения при добавлении элементов:
std::vector<Event> timeline;
timeline.reserve(app.size() + worker.size());


Теперь используем std::ranges::merge. Проекции сообщают алгоритму, что сравнивать нужно поле time, а не весь объект:
std::ranges::merge(app, worker, std::back_inserter(timeline),
{}, &Event::time, &Event::time);


Результат будет идти в порядке 10, 20, 30, 40. Если времена совпадут, алгоритм сохранит порядок элементов внутри каждого исходного списка. Записи с одинаковым временем не исчезают, merge переносит их все.

Проверим результат обычным обходом:
for (const Event& event : timeline) {
std::cout << event.time << " " << event.message << '\n';
}


Слияние работает за время, пропорциональное сумме длин списков, и удобно для логов, событий и результатов нескольких запросов.

📣 C++ Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍4🔥3