This media is not supported in your browser
VIEW IN TELEGRAM
Этот репозиторий собирает лучшие гайды, где вместо теории — реальные проекты, которые можно реализовать с нуля. Внутри есть десятки идей. В разделах по C++ и C# можно найти идеи разного уровня: работа с файлами, сетевое взаимодействие, графика, многопоточность и др. задачи.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18❤9🔥6
Почему push_back() во время обхода vector может привести к багу?
Потому что при добавлении нового элемента
Проблема в том, что range-based for тоже опирается на итераторы. И если внутри цикла вызвать:
контейнер может переехать в другую область памяти. Тогда цикл продолжит работу уже с невалидными итераторами, а это undefined behavior.
То есть внешне код выглядит безобидно, но в реальности может:
• работать “случайно нормально”
• пропускать элементы
• падать
• давать нестабильное поведение
Особенно неприятно, что такой баг может проявляться не всегда, а только при определенном размере контейнера.
🔥 У
📣 C++ Ready | #совет
Потому что при добавлении нового элемента
std::vector может перевыделить память. А после этого все итераторы, ссылки и указатели на его элементы становятся невалидными.Проблема в том, что range-based for тоже опирается на итераторы. И если внутри цикла вызвать:
v.push_back(5);
контейнер может переехать в другую область памяти. Тогда цикл продолжит работу уже с невалидными итераторами, а это undefined behavior.
То есть внешне код выглядит безобидно, но в реальности может:
• работать “случайно нормально”
• пропускать элементы
• падать
• давать нестабильное поведение
Особенно неприятно, что такой баг может проявляться не всегда, а только при определенном размере контейнера.
vector добавление элемента может инвалидировать итераторы. Менять контейнер во время его обхода нужно очень осторожно.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16👍5❤4
Например, регистры — это самый быстрый уровень памяти внутри CPU, кэш (L1/L2/L3) снижает latency за счёт локальности данных, RAM хранит рабочее состояние приложений, а SSD/HDD используются для персистентного хранения с существенно более высоким временем доступа.
На картинке — базовая иерархия памяти, взаимодействие CPU — cache — RAM — disk, а также упрощённая модель работы HDD и архитектура SSD.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤19👍9🔥6
Не копировать объект, а просто обменять: std::swap как базовый инструмент
Иногда нужно просто поменять значения двух переменных местами. Вручную это обычно делают через временную переменную, но в C++ для этого уже есть готовый и понятный инструмент —
Простой пример:
После вызова значения переменных меняются местами:
То же самое работает не только с числами, но и с контейнерами:
Такой обмен обычно дешевле и чище, чем ручное переприсваивание. А главное — сразу видно намерение: мы не “что-то присваиваем”, а именно меняем объекты местами.
🔥
📣 C++ Ready | #практика
Иногда нужно просто поменять значения двух переменных местами. Вручную это обычно делают через временную переменную, но в C++ для этого уже есть готовый и понятный инструмент —
std::swap.Простой пример:
int a = 10;
int b = 20;
std::swap(a, b);
std::cout << a << ' ' << b << '\n';
После вызова значения переменных меняются местами:
a == 20b == 10То же самое работает не только с числами, но и с контейнерами:
std::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 делает код проще и выразительнее: обмен значений — одной строкой и без лишнего шума.Please open Telegram to view this post
VIEW IN TELEGRAM
👍23❤6🔥6👎1
This media is not supported in your browser
VIEW IN TELEGRAM
Это структурированный обучающий сайт, где собрано более 200 уроков по C++, охватывающих как базовые, так и углублённые темы языка. Отдельное внимание уделено практике: на сайте есть задания, проекты и даже разборы создания игр, что позволяет применять знания в реальных задачах.
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤14🔥10👍6
Почему после push_back() нельзя слепо использовать старый итератор?
Потому что
Если при добавлении нового элемента текущей capacity уже не хватает, вектор перевыделяет память и переносит элементы в новое место.
После этого все итераторы, ссылки и указатели на старые элементы становятся невалидными.
В таком коде:
Если во время
Из-за этого баг особенно неприятный: код может
* работать “нормально” на маленьких примерах,
* ломаться только на других данных,
* проявляться нестабильно и не сразу.
Если после изменения
А если хочешь уменьшить шанс перевыделения памяти, можно заранее вызвать
🔥 У
📣 C++ Ready | #совет
Потому что
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 итераторы живут только до тех пор, пока контейнер не изменил свое хранилище.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8❤4🤝4😁1
В этой статье:
• Как создать окно SFML и настроить главный цикл с обработкой событий• Реализация singleton-контроллера для управления движением по клавишам• Подключение и отображение текстур в игровом цикле🔊 Советую продолжить читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍6🔥5👎1
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥28🤝5❤4😁1
Например, REST задаёт стандарт взаимодействия по HTTP, GraphQL — гибкую выборку данных, а gRPC — эффективную бинарную коммуникацию.
На схеме — основные области: основы (контракты, HTTP, stateless), паттерны (REST, RPC, WebSockets), безопасность (OAuth2, JWT, TLS), а также дизайн и эволюция API.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤18👍12🔥5
Почему lambda с [=] может работать не так, как ты ожидаешь?
Потому что
Но если внутри метода класса ты обращаешься к полям объекта, на самом деле захватывается не сам объект целиком, а указатель
В таком коде:
может казаться, что
Фактически lambda использует
Если к моменту выполнения задачи объект уже уничтожен, код получит висячий указатель и undefined behavior.
Из-за этого баг особенно неприятный:
Если нужен именно снимок данных на момент создания lambda, лучше захватывать его явно:
А если нужен сам объект, важно явно контролировать его lifetime.
🔥
📣 C++ Ready | #совет
Потому что
[=] копирует только локальные переменные из текущей области видимости.Но если внутри метода класса ты обращаешься к полям объекта, на самом деле захватывается не сам объект целиком, а указатель
this.В таком коде:
cpp id="r8n2fs"
pool.enqueue([=] {
process(data_);
});
может казаться, что
data_ безопасно скопирован внутрь lambda. Но это не так.Фактически lambda использует
this, а значит обращается к полю исходного объекта.Если к моменту выполнения задачи объект уже уничтожен, код получит висячий указатель и undefined behavior.
Из-за этого баг особенно неприятный:
• внешне всё выглядит как “захват по значению”
• код может долго работать нормально
• а потом упасть в асинхронном сценарии, где объект уже не живёт
Если нужен именно снимок данных на момент создания lambda, лучше захватывать его явно:
cpp id="x1kz7d"
auto data = data_;
pool.enqueue([data] {
process(data);
});
А если нужен сам объект, важно явно контролировать его lifetime.
🔥
[=] внутри метода класса не копирует поля объекта автоматически. Чаще всего ты захватываешь this, а не данные.Please open Telegram to view this post
VIEW IN TELEGRAM
❤8🔥5👍4
Нашёл статью, где автор разбирает два собственных блочных шифра на C++: ESCK-7 и Seal. Это интересный инженерный разбор того, как может быть устроено блочное шифрование.
В статье:
• структура блочного шифра и работа с 64-битными числами• генерация ключа и преобразования через XOR, NOT и циклические сдвиги• примеры функций шифрования, расшифровки и изменения ключа🔊 Продолжай читать на habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍4🔥3
Безопасное извлечение значения из map: try_emplace вместо лишних проверок!
Когда нужно добавить значение в
В C++17 для этого есть
Например:
Если ключа
Если ключ уже есть, значение не будет перезаписано:
Это удобно, когда значение дорого создавать или когда важно не затереть уже существующие данные.
Так код явно показывает намерение: добавить значение только при отсутствии ключа, без лишних проверок и случайного перезаписывания.
🔥
📣 C++ Ready | #практика
Когда нужно добавить значение в
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: только если ключа ещё нет.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14❤5👍3
Например, Factory помогает делегировать создание объектов, а Observer — удобно реализовать систему подписок и событий.
На картинке — 9 самых нужных паттернов, которые часто встречаются в реальных проектах и архитектуре.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥6❤4
Почему lambda с [=] может работать не так, как ты ожидаешь?
Потому что
Но если внутри метода класса ты обращаешься к полям объекта, на самом деле захватывается не сам объект целиком, а указатель
В таком коде:
может казаться, что
Фактически lambda использует
Если к моменту выполнения задачи объект уже уничтожен, код получит висячий указатель и undefined behavior.
Из-за этого баг особенно неприятный:
Если нужен именно снимок данных на момент создания lambda, лучше захватывать его явно:
А если нужен сам объект, важно явно контролировать его lifetime.
🔥
📣 C++ Ready | #совет
Потому что
[=] копирует только локальные переменные из текущей области видимости.Но если внутри метода класса ты обращаешься к полям объекта, на самом деле захватывается не сам объект целиком, а указатель
this.В таком коде:
cpp id="r8n2fs"
pool.enqueue([=] {
process(data_);
});
может казаться, что
data_ безопасно скопирован внутрь lambda. Но это не так.Фактически lambda использует
this, а значит обращается к полю исходного объекта.Если к моменту выполнения задачи объект уже уничтожен, код получит висячий указатель и undefined behavior.
Из-за этого баг особенно неприятный:
• внешне всё выглядит как “захват по значению”
• код может долго работать нормально
• а потом упасть в асинхронном сценарии, где объект уже не живёт
Если нужен именно снимок данных на момент создания lambda, лучше захватывать его явно:
cpp id="x1kz7d"
auto data = data_;
pool.enqueue([data] {
process(data);
});
А если нужен сам объект, важно явно контролировать его lifetime.
[=] внутри метода класса не копирует поля объекта автоматически. Чаще всего ты захватываешь this, а не данные.Please open Telegram to view this post
VIEW IN TELEGRAM
❤12🔥7👍4
Почему std::optional<T> часто понимают неправильно?
Потому что
То есть если значение есть, объект
Например:
здесь
Из-за этого у optional другая семантика:
Поэтому
Но если тебе нужна именно не-владеющая ссылка на уже существующий объект,
🔥
📣 C++ Ready | #совет
Потому что
optional выглядит как “объект, которого может не быть”, и из-за этого его легко мысленно приравнять к указателю. Но это другая модель.std::optional<T> хранит значение внутри себя.То есть если значение есть, объект
T находится прямо внутри optional, а не где-то отдельно в памяти.Например:
std::optional<std::string> name = "Gus";
здесь
optional не указывает на строку — он содержит строку внутри себя.Из-за этого у optional другая семантика:
• копирование optional копирует и само значение
• перемещение optional перемещает значение
• optional не подходит как замена ссылке
• отсутствие значения — это отдельное состояние самого объекта, а не nullptr
Поэтому
optional удобен, когда функция может вернуть значение или не вернуть ничего:std::optional<User> find_user(int id);
Но если тебе нужна именно не-владеющая ссылка на уже существующий объект,
optional для этого обычно не лучший инструмент.std::optional<T> — это контейнер для “значение есть или его нет”, а не просто красивый указатель.Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍4🔥3