Небольшая программа превращает обычный текстовый словарик в живую тренировку памяти: вопросы появляются случайно, а каждый ответ тут же показывает, насколько ты внимателен.
В этой задаче узнаешь:
• Как превращать список слов в живые вопросы;
• Почему короткие сессии повторения укрепляют память лучше зубрёжки;
• Что меняется, когда ответы сразу показывают твой прогресс.
Пара строк текста в файле — и у тебя есть личный учитель, который терпеливо задаёт вопросы хоть каждый день.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥9❤5👎1🤝1
Например, DNS-сервер преобразует доменное имя в IP-адрес, а кеш-сервер ускоряет отдачу данных, снижая нагрузку на базу.
На картинке — фундамент серверной инфраструктуры, без которой не работает ни одно современное приложение.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18🔥8❤4
Заменить значение и забрать старое — std::exchange!
Иногда нужно “переключить” переменную на новое значение и при этом сохранить старое: например, сбросить флаг, обнулить указатель, забрать ресурс у объекта. Вместо двух строк и временной переменной есть удобная функция
Сначала типичный “ручной” вариант:
Теперь то же самое одной строкой:
Частый практический кейс — “забрать” указатель и обнулить его, чтобы избежать повторного использования:
И ещё один популярный пример — move-конструктор, где нужно забрать ресурс и оставить исходный объект в безопасном состоянии:
🔥
📣 C++ Ready | #практика
Иногда нужно “переключить” переменную на новое значение и при этом сохранить старое: например, сбросить флаг, обнулить указатель, забрать ресурс у объекта. Вместо двух строк и временной переменной есть удобная функция
std::exchange.Сначала типичный “ручной” вариант:
int old = value;
value = 0;
use(old);
Теперь то же самое одной строкой:
std::exchange возвращает старое значение и записывает новое:int old = std::exchange(value, 0);
use(old);
Частый практический кейс — “забрать” указатель и обнулить его, чтобы избежать повторного использования:
T* take_ptr(T*& p) {
return std::exchange(p, nullptr);
}И ещё один популярный пример — move-конструктор, где нужно забрать ресурс и оставить исходный объект в безопасном состоянии:
struct Buffer {
int* data = nullptr;
Buffer(Buffer&& other) noexcept
: data(std::exchange(other.data, nullptr)) {}
};std::exchange делает намерение явным: “забрать старое, поставить новое” — меньше кода, меньше шансов забыть сбросить состояние.Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥11❤6
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🤝32🔥18❤5👍1
В этой статье:
• Понять, как RAII помогает строить архитектуру и инварианты• Увидеть примеры управления разными ресурсами (не только памятью)• Научиться делать код устойчивым к исключениям и “утечкам ответственности”🔊 Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍6❤5😁1
Безопасный “побитовый каст” без UB — std::bit_cast!
Иногда нужно посмотреть на биты значения: получить IEEE754-представление
Многие делают это через
Сначала типичный “ручной” (опасный) вариант:
Теперь то же самое правильно одной строкой:
Частый практический кейс — быстро проверить знак/экспоненту
Ещё один популярный пример — получить “сырой”
И обратная операция — восстановить значение из битов (тоже безопасно, если размер совпадает):
🔥
📣 C++ Ready | #практика
Иногда нужно посмотреть на биты значения: получить IEEE754-представление
float, собрать/разобрать сетевой пакет, сделать хеш по битам, интерпретировать double как uint64_t.Многие делают это через
reinterpret_cast или “указательную магию” — и ловят UB из-за strict aliasing и выравнивания.Сначала типичный “ручной” (опасный) вариант:
float f = 1.0f;
auto u = *reinterpret_cast<std::uint32_t*>(&f); // UB!
use(u);
Теперь то же самое правильно одной строкой:
std::bit_cast (C++20) копирует биты между типами одинакового размера:float f = 1.0f;
auto u = std::bit_cast<std::uint32_t>(f);
use(u);
Частый практический кейс — быстро проверить знак/экспоненту
float без математики:bool is_negative(float x) {
auto bits = std::bit_cast<std::uint32_t>(x);
return (bits >> 31) != 0;
}Ещё один популярный пример — получить “сырой”
uint64_t из double для стабильного сравнения/логирования битов:std::uint64_t raw_bits(double d) {
return std::bit_cast<std::uint64_t>(d);
}И обратная операция — восстановить значение из битов (тоже безопасно, если размер совпадает):
double from_bits(std::uint64_t bits) {
return std::bit_cast<double>(bits);
}std::bit_cast делает намерение явным: “мне нужны биты, а не преобразование значения” — без reinterpret_cast, без строгого алиасинга, меньше шансов поймать UB.Please open Telegram to view this post
VIEW IN TELEGRAM
❤14🔥9👍5
This media is not supported in your browser
VIEW IN TELEGRAM
Бесплатный “one-stop shop” для подготовки к USACO: структурированные разделы от Intro и Bronze до Platinum/Advanced, где в каждом модуле есть объяснение темы, советы по реализации, подборка задач для практики и разборы/редакции
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍8🔥5🤝1
Почему std::move не “перемещает”?
Многие думают, что
Проблема начинается, когда после
После перемещения объект обязан оставаться валидным, но его состояние становится неопределённым (у
Правильное правило простое:
•
• после этого
🔥 Итог:
📣 C++ Ready | #совет
Многие думают, что
std::move(x) физически “переносит” данные и очищает x. Но std::move ничего не двигает — это всего лишь приведение к rvalue-ссылке, то есть сигнал компилятору: “этот объект можно перемещать”.Проблема начинается, когда после
std::move мы продолжаем пользоваться объектом как раньше:std::string s = "hello";
std::string a = std::move(s);
std::cout << s; // ❌ логическая ошибка
После перемещения объект обязан оставаться валидным, но его состояние становится неопределённым (у
std::string часто будет пусто, но полагаться на это нельзя). Поэтому любые “проверю что осталось” и “ещё раз использую” — источник багов.Правильное правило простое:
•
std::move(x) = “я отказываюсь от значения x”• после этого
x можно только: присвоить новое значение / уничтожить / вызвать безопасные операции, не зависящие от содержимого.std::move — не перенос, а разрешение на перенос. Если ты пишешь std::move, считай, что “объект дальше мне не нужен” — так код становится предсказуемым и без скрытых сюрпризов.Please open Telegram to view this post
VIEW IN TELEGRAM
👍22🔥9❤6🤝2
Антипаттерн: # define DEBUG 1 vs NDEBUG
Часто для отладочного кода делают что-то вроде
Работает? Да.
Надёжно? Не всегда.
Проблема в том, что такой
В стандарте C++ уже есть специальный макрос для этого —
Именно на него завязаны
Плохой вариант:
Если забыть убрать
Правильный вариант — ориентироваться на
Теперь всё согласовано:
• debug-сборка → логирование и проверки есть
• release (
Точно так же стоит писать и свои отладочные макросы:
🔥 Использование
📣 C++ Ready | #практика
Часто для отладочного кода делают что-то вроде
#define DEBUG 1 и оборачивают всё в #ifdef DEBUG.Работает? Да.
Надёжно? Не всегда.
Проблема в том, что такой
DEBUG — не стандартный, и он легко расходится с реальным типом сборки. В итоге можно случайно оставить отладочный код в релизе.В стандарте C++ уже есть специальный макрос для этого —
NDEBUG. Если NDEBUG не определён, значит это debug-сборка. Если NDEBUG определён, значит релиз.Именно на него завязаны
assert и многие стандартные проверки.Плохой вариант:
#define DEBUG 1
void foo(int x) {
#ifdef DEBUG
std::cout << "x = " << x << "\n";
#endif
work(x);
}
Если забыть убрать
DEBUG или определить его не там — отладочный код спокойно уедет в прод.Правильный вариант — ориентироваться на
NDEBUG:void foo(int x) {
#ifndef NDEBUG
std::cerr << "x = " << x << "\n";
#endif
work(x);
}Теперь всё согласовано:
• debug-сборка → логирование и проверки есть
• release (
-DNDEBUG) → код полностью вырезается компиляторомТочно так же стоит писать и свои отладочные макросы:
#ifndef NDEBUG
#define DBG_LOG(msg) std::cerr << msg << "\n"
#else
#define DBG_LOG(msg) ((void)0)
#endif
NDEBUG — это не мелочь, а дисциплина сборки: отладочный код никогда не попадёт в релиз случайно, и всё поведение будет согласовано со стандартными механизмами C++.Please open Telegram to view this post
VIEW IN TELEGRAM
❤22👍12🔥7
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥22🤝11❤6👍2