-
Авторский канал по разработке на C и C++. Ресурсы, обучения, задачи, шпаргалки. Ежедневно информация пополняется! Автор: @energy_it
Удаление элементов без erase-remove идиомы: `std::erase_if`
Когда нужно удалить элементы из контейнера по условию, в старом C++ часто использовали связку std::remove_if + erase. Работает, но выглядит шумно и не сразу читается.
В C++20 для этого есть std::erase_if.
Например, удалим все отрицательные значения из std::vector:
std::vector<int> values{3, -1, 7, -5, 10};
std::erase_if(values, [](int x) {
return x < 0;
});for (int x : values) {
std::cout << x << ' ';
}
// 3 7 10std::erase_if пришлось бы писать длиннее:values.erase(
std::remove_if(values.begin(), values.end(), [](int x) {
return x < 0;
}),
values.end()
);
std::erase_if работает не только с std::vector, но и с другими стандартными контейнерами:std::map<std::string, int> counters{
{"ok", 10},
{"errors", 0},
{"warnings", 3}
};
std::erase_if(counters, [](const auto& item) {
return item.second == 0;
});std::erase_if делает удаление по условию коротким и читаемым: одно действие — одна понятная строка.
☕️ Code․mu Tasker — бесплатный практический задачник по плюсам!
Здесь собрано 100 упражнений, распределённых по 10 уровням, которые помогут вам отработать базовые конструкции языка, принципы ООП, работу с библиотекой STL, алгоритмы и многое другое.
📌 Оставляю ссылочку: code.mu
📣 C++ Ready | #ресурс
📂 Напоминалка по памяти и накопителям!
Например, RAM используется для временного хранения данных во время работы программы, а ROM хранит постоянную информацию вроде прошивки.
На картинке — основные типы памяти и storage: RAM, ROM, SRAM, DRAM и др.
Сохрани, чтобы не потерять!
📣 C++ Ready | #ресурс
📂 Напоминалка для работы с OOP Design Patterns!
Например, Factory помогает делегировать создание объектов, а Observer — удобно реализовать систему подписок и событий.
На картинке — 9 самых нужных паттернов, которые часто встречаются в реальных проектах и архитектуре.
Сохрани, чтобы не потерять!
📣 C++ Ready | #ресурс
🔥База платных курсов и книг по программированию на весь 2026 год!🔥
Канал новый, потому что слишком много людей ждут халявы.
Тут всё, что обычно стоит тысячи:
— Авторские курсы, которые не найти в открытом доступе
— Самые свежие книги для старта
— Всё, что нужно, чтобы за полгода вырасти от мидла до сеньора
➡️ Залетайте, пока есть доступ!
Почему lambda с [=] может работать не так, как ты ожидаешь?
Потому что [=] копирует только локальные переменные из текущей области видимости.
Но если внутри метода класса ты обращаешься к полям объекта, на самом деле захватывается не сам объект целиком, а указатель this.
В таком коде:
cpp id="r8n2fs"
pool.enqueue([=] {
process(data_);
});
data_ безопасно скопирован внутрь lambda. Но это не так.this, а значит обращается к полю исходного объекта.• внешне всё выглядит как “захват по значению”
• код может долго работать нормально
• а потом упасть в асинхронном сценарии, где объект уже не живёт
cpp id="x1kz7d"
auto data = data_;
pool.enqueue([data] {
process(data);
});
[=] внутри метода класса не копирует поля объекта автоматически. Чаще всего ты захватываешь this, а не данные.
👩💻 Рассмотрим std::bitset — быстрый и понятный способ работы с битами!С его помощью можно удобно хранить и обрабатывать флаги, состояния и биты без возни с ручными масками и побитовыми операциями. Это особенно полезно в системном программировании, играх и embedded-разработке.
📣 C++ Ready | #шпора
Почему после push_back() нельзя слепо использовать старый итератор?
Потому что std::vector хранит элементы в непрерывной области памяти.
Если при добавлении нового элемента текущей capacity уже не хватает, вектор перевыделяет память и переносит элементы в новое место.
После этого все итераторы, ссылки и указатели на старые элементы становятся невалидными.
В таком коде:
std::vector<int> v = {1, 2, 3};
auto it = v.begin();
v.push_back(4);
std::cout << *it << "\n";it мог указывать на элемент в старом буфере памяти.push_back() произошел reallocation, разыменование it — это уже undefined behavior.vector тебе снова нужен итератор, его лучше получить заново.reserve().vector итераторы живут только до тех пор, пока контейнер не изменил свое хранилище.
Не копировать объект, а просто обменять: std::swap как базовый инструмент
Иногда нужно просто поменять значения двух переменных местами. Вручную это обычно делают через временную переменную, но в C++ для этого уже есть готовый и понятный инструмент — std::swap.
Простой пример:
int a = 10;
int b = 20;
std::swap(a, b);
std::cout << a << ' ' << b << '\n';
a == 20b == 10std::vector<int> x{1, 2, 3};
std::vector<int> y{4, 5};
std::swap(x, y);
std::cout << x.size() << ' ' << y.size() << '\n';std::swap делает код проще и выразительнее: обмен значений — одной строкой и без лишнего шума.
Почему push_back() во время обхода vector может привести к багу?
Потому что при добавлении нового элемента std::vector может перевыделить память. А после этого все итераторы, ссылки и указатели на его элементы становятся невалидными.
Проблема в том, что range-based for тоже опирается на итераторы. И если внутри цикла вызвать:
v.push_back(5);
vector добавление элемента может инвалидировать итераторы. Менять контейнер во время его обхода нужно очень осторожно.
Разбираем безопасное побитовое преобразование типов!
Сейчас научимся преобразовывать данные одного типа в другой без неопределённого поведения — с помощью функции std::bit_cast.
Сначала подключим необходимые библиотеки из стандартной поставки:
#include <bit> // std::bit_cast
#include <cstdint> // uint32_t
#include <iostream>
#include <iomanip> // std::hex, std::setw, std::setfill
uint32_t, чтобы увидеть его внутреннее битовое представление:float value = 3.1415926f;
uint32_t raw = std::bit_cast<uint32_t>(value);
std::cout << "Биты числа: 0x"
<< std::hex << std::setw(8) << std::setfill('0') << raw << '\n';
float restored = std::bit_cast<float>(raw);
std::cout << std::dec << "Восстановлено: " << restored << '\n';
Биты числа: 0x40490fda
Восстановлено: 3.14159
👩💻 Разберём циклы с диапазоном и auto — способ проходить по контейнеру без индексов и явных итераторов!С их помощью можно автоматически определять тип переменной, изменять элементы контейнера по ссылке, безопасно обходить коллекции без копирования, удобно распаковывать пары и кортежи
📣 C++ Ready | #шпора
Меньше .first и .second: разбираем pair и tuple по-человечески!
Когда работаешь с std::pair, std::tuple или элементами std::map, код быстро зарастает обращениями вроде .first, .second и std::get<0>(). Читать это неудобно, особенно если таких мест много.
В C++17 для этого есть structured bindings. Они позволяют сразу разложить объект на именованные переменные.
Например, так можно пройтись по std::map:
#include <iostream>
#include <map>
#include <string>
std::map<std::string, int> scores{
{"alice", 10},
{"bob", 20}
};
for (const auto& [name, score] : scores) {
std::cout << name << ": " << score << '\n';
}
for (const auto& item : scores) {
std::cout << item.first << ": "
<< item.second << '\n';
}std::pair:std::pair p{"error", 500};
auto [text, code] = p;
std::cout << text << ' ' << code << '\n';.first и .second появляются нормальные имена переменных, которые сразу передают смысл.
Как shared_ptr может привести к утечке памяти?
Потому что подсчет ссылок не умеет сам разрывать циклы.
Если два объекта держат друг друга через std::shared_ptr, их счетчики ссылок никогда не станут равны нулю. Даже когда внешний код уже “отпустил” оба объекта, они продолжают владеть друг другом.
Например, в такой схеме:
struct A {
std::shared_ptr<B> b;
};
struct B {
std::shared_ptr<A> a;
};A владеет B, а B владеет A.shared_ptr не гарантирует автоматическое освобождение памяти во всех случаях.struct B {
std::weak_ptr<A> a;
};std::weak_ptr не увеличивает счетчик владения, поэтому цикл исчезает, и объекты могут быть корректно уничтожены.shared_ptr считает владельцев, но не умеет сам разрывать циклы. Для этого нужен weak_ptr.
✍️ CyberForum — крупнейшее сообщество разработчиков с разделами по C++ и C#!
Форум, где можно обсуждать задачи, получать помощь и разбирать кейсы из разработки. Есть активные разделы по C++ и C#: обсуждение синтаксиса, разбор ошибок, советы по обучению и практическая помощь. Форум можно использовать как источник знаний, особенно когда требуется разобраться в конкретной задаче или посмотреть, как её решают другие разработчик.
📌 Оставляю ссылочку: cyberforum.ru
📣 C++ Ready | #сайт
❤️ Free Programming Books — огромная коллекция бесплатных книг по программированию!
В этом репозитории собраны десятки книг по разным языкам и направлениям, таким как C/C++ и многое другое. Всё разложено по категориям, поэтому можно быстро найти нужную тему. Здесь есть как базовые учебники по синтаксису и указателям, так и более серьёзные материалы по памяти, низкоуровневой работе и системному программированию.
Оставляю ссылочку: GitHub 📱
Почему std::optional<T> часто понимают неправильно?
Потому что optional выглядит как “объект, которого может не быть”, и из-за этого его легко мысленно приравнять к указателю. Но это другая модель.std::optional<T> хранит значение внутри себя.
То есть если значение есть, объект T находится прямо внутри optional, а не где-то отдельно в памяти.
Например:
std::optional<std::string> name = "Gus";
optional не указывает на строку — он содержит строку внутри себя.• копирование optional копирует и само значение
• перемещение optional перемещает значение
• optional не подходит как замена ссылке
• отсутствие значения — это отдельное состояние самого объекта, а не nullptr
optional удобен, когда функция может вернуть значение или не вернуть ничего:std::optional<User> find_user(int id);
optional для этого обычно не лучший инструмент.std::optional<T> — это контейнер для “значение есть или его нет”, а не просто красивый указатель.
Почему lambda с [=] может работать не так, как ты ожидаешь?
Потому что [=] копирует только локальные переменные из текущей области видимости.
Но если внутри метода класса ты обращаешься к полям объекта, на самом деле захватывается не сам объект целиком, а указатель this.
В таком коде:
cpp id="r8n2fs"
pool.enqueue([=] {
process(data_);
});
data_ безопасно скопирован внутрь lambda. Но это не так.this, а значит обращается к полю исходного объекта.• внешне всё выглядит как “захват по значению”
• код может долго работать нормально
• а потом упасть в асинхронном сценарии, где объект уже не живёт
cpp id="x1kz7d"
auto data = data_;
pool.enqueue([data] {
process(data);
});
[=] внутри метода класса не копирует поля объекта автоматически. Чаще всего ты захватываешь this, а не данные.
Безопасное извлечение значения из map: try_emplace вместо лишних проверок!
Когда нужно добавить значение в std::map, если ключа ещё нет, код часто превращается в проверку через find, а потом отдельную вставку. Работает, но получается многословно.
В C++17 для этого есть try_emplace. Он добавляет элемент только если такого ключа ещё нет.
Например:
#include <map>
#include <string>
#include <iostream>
std::map<std::string, int> counters;
counters.try_emplace("errors", 0);
"errors" ещё не было, он появится со значением 0.counters["errors"] = 5;
counters.try_emplace("errors", 0);
std::cout << counters["errors"] << '\n'; // 5
try_emplace также возвращает пару: итератор и флаг, была ли вставка выполнена.auto [it, inserted] = counters.try_emplace("warnings", 0);
if (inserted) {
std::cout << "created\n";
} else {
std::cout << "already exists\n";
}try_emplace помогает аккуратно добавлять элементы в map: только если ключа ещё нет.
👀 Хочешь понять криптографию не только на уровне терминов, а через код?
Нашёл статью, где автор разбирает два собственных блочных шифра на C++: ESCK-7 и Seal. Это интересный инженерный разбор того, как может быть устроено блочное шифрование.
В статье:• структура блочного шифра и работа с 64-битными числами• генерация ключа и преобразования через XOR, NOT и циклические сдвиги• примеры функций шифрования, расшифровки и изменения ключа
🔊 Продолжай читать на habr!
📂 Принципы проектирования и архитектуры API!
Например, REST задаёт стандарт взаимодействия по HTTP, GraphQL — гибкую выборку данных, а gRPC — эффективную бинарную коммуникацию.
На схеме — основные области: основы (контракты, HTTP, stateless), паттерны (REST, RPC, WebSockets), безопасность (OAuth2, JWT, TLS), а также дизайн и эволюция API.
Сохрани, чтобы не потерять!
📣 C++ Ready | #ресурс
😎 Нашёл полезную статью на Хабре — отличный пример, как начать писать простую игру на C++ с помощью SFML!
В этой статье:• Как создать окно SFML и настроить главный цикл с обработкой событий• Реализация singleton-контроллера для управления движением по клавишам• Подключение и отображение текстур в игровом цикле
🔊 Советую продолжить читать на Habr!
🧐 Ravesli — подробный курс по C++ с нуля!
Это структурированный обучающий сайт, где собрано более 200 уроков по C++, охватывающих как базовые, так и углублённые темы языка. Отдельное внимание уделено практике: на сайте есть задания, проекты и даже разборы создания игр, что позволяет применять знания в реальных задачах.
📌 Оставляю ссылочку: ravesli.com
📣 C++ Ready | #сайт
📂 Напоминалка по иерархии памяти и работе storage!
Например, регистры — это самый быстрый уровень памяти внутри CPU, кэш (L1/L2/L3) снижает latency за счёт локальности данных, RAM хранит рабочее состояние приложений, а SSD/HDD используются для персистентного хранения с существенно более высоким временем доступа.
На картинке — базовая иерархия памяти, взаимодействие CPU — cache — RAM — disk, а также упрощённая модель работы HDD и архитектура SSD.
Сохрани, чтобы не потерять!
📣 C++ Ready | #ресурс
🐱 Project-Based Learning — обучение через проекты!
Этот репозиторий собирает лучшие гайды, где вместо теории — реальные проекты, которые можно реализовать с нуля. Внутри есть десятки идей. В разделах по C++ и C# можно найти идеи разного уровня: работа с файлами, сетевое взаимодействие, графика, многопоточность и др. задачи.
Оставляю ссылочку: GitHub 📱
📂 Напоминалка по HTTP-статусам!
Например, код 200 означает, что всё прошло успешно, а 404 сообщает, что страница не найдена.
Очень полезно держать под рукой, когда работаешь с API или отлаживаешь backend.
На картинке показаны самые часто используемые статусы от 100 до 599.
Сохрани, чтобы не забыть!
📣 C++ Ready | #ресурс
💅 Beautiful — нейросеть для создания презентаций!
Это AI-инструмент для быстрого создания профессиональных презентаций. Достаточно добавить текст и идеи, а нейросеть автоматически подбирает дизайн, выравнивает элементы и формирует слайды. Встроенные умные шаблоны помогают делать презентации аккуратными без ручной настройки — AI сам адаптирует макет при добавлении контента.
📌 Оставляю ссылочку: beautiful.ai
📣 C++ Ready | #ресурс
📂 Шпаргалка по вычислительным архитектурам!
Например, CPU хорошо справляется с логикой, ветвлениями и задачами с низкой задержкой. GPU — про массовый параллелизм: подходит для обработки больших массивов данных, графики и вычислений.
На картинке — наглядное сравнение архитектуры, модели вычислений и типичных сценариев применения для каждого типа процессоров.
Сохрани, чтобы не потерять!
📣 C++ Ready | #ресурс
😍 PVS-Studio Blog — технические статьи по коду и разработке!
Здесь публикуются подробные разборы ошибок, уязвимостей и практик разработки. Основной фокус на статический анализ кода и реальные кейсы из проектов, включая разборы популярных open-source решений. Блог активно покрывает C++ и C#: публикуются статьи по анализу, поиску багов, особенностям работы компиляторов и практике.
📌 Оставляю ссылочку: pvs-studio.ru
📣 C++ Ready | #сайт
Почему emplace_back() не всегда лучше push_back()?
Есть популярное заблуждение, что emplace_back() всегда быстрее. Но это не так.push_back() добавляет в контейнер уже готовый объект.emplace_back() конструирует объект прямо на месте из переданных аргументов.
Например:
v.emplace_back("world");vector, и это действительно удобно.std::string s = "hello";
v.push_back(s);
v.emplace_back(s);
emplace_back() полезен, когда ты передаешь аргументы конструктора.push_back() — когда у тебя уже есть готовое значение.emplace_back() — не универсально лучший вариант. Используй его там, где нужен именно in-place construction.