Почему 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
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14🔥6👍4
This media is not supported in your browser
VIEW IN TELEGRAM
В этом репозитории собраны десятки книг по разным языкам и направлениям, таким как C/C++ и многое другое. Всё разложено по категориям, поэтому можно быстро найти нужную тему. Здесь есть как базовые учебники по синтаксису и указателям, так и более серьёзные материалы по памяти, низкоуровневой работе и системному программированию.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤7🤝6
Удаление элементов без erase-remove идиомы: `std::erase_if`
Когда нужно удалить элементы из контейнера по условию, в старом C++ часто использовали связку
В C++20 для этого есть
Например, удалим все отрицательные значения из
После этого в контейнере останутся только положительные значения:
Без
Новая версия лучше показывает намерение: мы не “переставляем элементы и потом стираем хвост”, а просто удаляем всё, что подходит под условие.
Так можно аккуратно чистить контейнеры без ручных циклов и лишнего служебного кода.
🔥
📣 C++ Ready | #практика
Когда нужно удалить элементы из контейнера по условию, в старом 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 10Без
std::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 делает удаление по условию коротким и читаемым: одно действие — одна понятная строка.Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥5❤3
Например, Indexing ускоряет поиск по таблицам, а Sharding помогает разделить большие объёмы данных между несколькими узлами.
На картинке — 7 стратегий масштабирования БД: индексы, materialized views, denormalization, vertical scaling, caching, replication и sharding.
Сохрани, чтобы не потерять!
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
🔥18❤5👍3👎1🤝1
В этой статье:
• как устроена базовая камера и выпуск лучей в сцену
• как найти пересечение луча со сферой и рассчитать цвет пикселя
• как добавить материалы, отражения, тени и получить объёмную картинку🔊 Продолжай читать на habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤17👍7🤝3
Почему
Потому что
В таком контексте это forwarding reference, которая может принять и временный объект, и обычную lvalue-переменную.
Например:
Здесь в
Но внутри функции мы пишем:
И этим насильно превращаем
В итоге
То есть проблема не в самом
Для perfect forwarding нужно использовать:
• lvalue остается lvalue
• rvalue остается rvalue
А
🔥 В forwarding-коде
📣 C++ Ready | #совет
std::move внутри forwarding-функции может быть ошибкой?Потому что
T&& в шаблоне — это не всегда rvalue-ссылка.В таком контексте это forwarding reference, которая может принять и временный объект, и обычную lvalue-переменную.
Например:
std::string s = "hello";
wrapper(s);
Здесь в
wrapper передается lvalue.Но внутри функции мы пишем:
process(std::move(value));
И этим насильно превращаем
value в rvalue.В итоге
process() может переместить данные из объекта s, хотя вызывающий код передавал обычную переменную и не ожидал, что из нее что-то “заберут”.То есть проблема не в самом
std::move, а в том, что он всегда делает аргумент кандидатом на перемещение.Для perfect forwarding нужно использовать:
template <class T>
void wrapper(T&& value) {
process(std::forward<T>(value));
}
std::forward<T> сохраняет исходную категорию значения:• lvalue остается lvalue
• rvalue остается rvalue
А
std::move всегда говорит: “можно перемещать”.std::move часто слишком агрессивен. Если хочешь сохранить поведение аргумента — используй std::forward<T>.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍5❤4
Многопоточность — это не запуск нескольких thread. В реальных системах приходится управлять shared state, очередями задач, producer/consumer-потоками, read/write доступом и координацией выполнения.
На картинке — популярные multithreading patterns: read-write lock, thread pool, producer-consumer, future/promise и другие подходы, которые помогают организовать concurrent-код.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13🔥7🤝5
Быстро удаляем пробелы в начале и в конце строки!
Когда мы читаем строки из файла, пользовательского ввода или сетевого запроса — часто получаем "шум": пробелы, табы, переводы строк.
Во многих языках есть встроенные
Начнём с подключения нужных заголовков:
Теперь реализуем функцию
• пропускает все пробелы с начала строки;
• пропускает все пробелы с конца;
• возвращает обрезанную часть как новую строку:
Проверим, как это работает на примере строки с лишними пробелами и переводами строк:
Результат выполнения:
🔥 Теперь у тебя есть удобная функция, которая безопасно удаляет "мусор" по краям строки.
📣 C++ Ready | #практика
Когда мы читаем строки из файла, пользовательского ввода или сетевого запроса — часто получаем "шум": пробелы, табы, переводы строк.
Во многих языках есть встроенные
trim()-функции, но в C++ стандартной такой нет. Зато её легко реализовать самому — компактно, эффективно и без сторонних зависимостей.Начнём с подключения нужных заголовков:
#include <string>
#include <cctype> // std::isspace
#include <algorithm>
#include <iostream>
Теперь реализуем функцию
trim, которая:• пропускает все пробелы с начала строки;
• пропускает все пробелы с конца;
• возвращает обрезанную часть как новую строку:
std::string trim(const std::string& s) {
auto start = std::find_if_not(s.begin(), s.end(), ::isspace);
auto end = std::find_if_not(s.rbegin(), s.rend(), ::isspace).base();
return (start < end) ? std::string(start, end) : "";
}Проверим, как это работает на примере строки с лишними пробелами и переводами строк:
std::string raw = " \t\n Hello, world! \n ";
std::string cleaned = trim(raw);
std::cout << "[" << cleaned << "]\n";
Результат выполнения:
[Hello, world!]
🔥 Теперь у тебя есть удобная функция, которая безопасно удаляет "мусор" по краям строки.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤8👍4