Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21❤13👍6🤝2
Docker — это набор связанных частей: сборка и хранение образов, запуск контейнеров, сеть и данные. Вместе они дают изоляцию и одинаковый запуск приложения на любой машине.
На картинке показано, из чего состоит Docker и как эти части взаимодействуют между собой. Удобная схема для понимания базы и быстрого повторения.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍7❤4
Sanitizers в C++: что включить, чтобы не ловить баги в проде
Если команда редко запускает sanitizers, то ошибки памяти и UB почти всегда доезжают до релиза. Поэтому их лучше включить как обычную часть разработки.
Для ежедневной сборки обычно хватает такого набора:
Для многопоточного кода лучше запускать отдельный прогон:
Пример, который
Без sanitizer такой баг может долго жить незаметно, но с sanitizer вы получаете падение в точке ошибки.
🔥 Удобная схема: локально вы работаете с
📣 C++ Ready | #практика
Если команда редко запускает sanitizers, то ошибки памяти и UB почти всегда доезжают до релиза. Поэтому их лучше включить как обычную часть разработки.
ASan хорошо ловит выходы за границы, use-after-free и double free. UBSan показывает разные виды undefined behavior, а TSan находит гонки и проблемы синхронизации.Для ежедневной сборки обычно хватает такого набора:
-fsanitize=address,undefined -fno-omit-frame-pointer -g -O1
Для многопоточного кода лучше запускать отдельный прогон:
-fsanitize=thread -g -O1
Пример, который
ASan поймает сразу:std::vector<int> v{1, 2, 3};
int x = v[5];Без sanitizer такой баг может долго жить незаметно, но с sanitizer вы получаете падение в точке ошибки.
ASan + UBSan, в PR вы гоняете те же проверки, а TSan выносите в отдельный CI-job.Please open Telegram to view this post
VIEW IN TELEGRAM
❤23👍8🔥4
Почему new int и make_unique<int>() ведут себя по-разному?
Это одна из самых коварных “мелочей”: для фундаментальных типов
Вот эта строка создаёт
А вот это — value-initialization, и
🔥 Если хочешь гарантированную инициализацию — используй
📣 C++ Ready | #совет
Это одна из самых коварных “мелочей”: для фундаментальных типов
new int не инициализирует значение, ты получаешь мусор (а чтение такого значения — уже UB).Вот эта строка создаёт
int с неопределённым содержимым:new int
А вот это — value-initialization, и
int станет 0:new int()
std::make_unique<int>() как раз создаёт объект с value-initialization, поэтому *p2 будет нулём, а *p1 — “рандом”:auto p2 = std::make_unique<int>();
{}/():Please open Telegram to view this post
VIEW IN TELEGRAM
❤17👍10🔥6
В этой статье:
• Как устроены базовые запросы и ответы (GET/POST), и как формировать маршруты;
• Как за пару функций запустить простой HTTP-сервер и обработчики эндпоинтов;
• Примеры работы с параметрами, JSON/формами и типичные “грабли” интеграции🔊 Продолжай читать на Typevar!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥8❤4
👍15🔥9❤5👎2
This media is not supported in your browser
VIEW IN TELEGRAM
Внутри — фундаментальные темы: переменные и типы данных, арифметика, условные операторы (if/else), циклы, массивы, функции, а также работа с header files.
Please open Telegram to view this post
VIEW IN TELEGRAM
👎15👍7❤6🤝4
Почему T* + size до сих пор ломает код, и чем помогает std::span?
На бумаге пара
Код становится проще читать, а шанс рассинхронизировать указатель и размер уходит сам собой.
Если функция должна менять данные, используйте
Есть важный момент:
🔥 Если коротко,
📣 C++ Ready | #практика
На бумаге пара
T* и size выглядит аккуратно. На практике эти аргументы часто расходятся, и после этого вы получаете выход за границы в месте, которое кажется невинным.void process(const int* data, std::size_t size) {
for (std::size_t i = 0; i < size; ++i) {
use(data[i]);
}
}
std::vector<int> v{1, 2, 3};
process(v.data(), 5); // size передали неверноstd::span решает именно эту часть проблемы, потому что вы передаете диапазон как единый объект.void process(std::span<const int> data) {
for (int x : data) {
use(x);
}
}
std::vector<int> v{1, 2, 3};
std::array<int, 3> a{4, 5, 6};
int raw[] = {7, 8, 9};
process(v);
process(a);
process(raw);Код становится проще читать, а шанс рассинхронизировать указатель и размер уходит сам собой.
Если функция должна менять данные, используйте
std::span<int>, а если только читать, оставляйте std::span<const T>.Есть важный момент:
std::span не владеет памятью. Он просто ссылается на уже существующие данные, поэтому источник данных должен жить дольше самого span.std::span<int> bad_span() {
std::vector<int> tmp{1, 2, 3};
return std::span<int>(tmp); // dangling
}std::span не делает магию, но он убирает один из самых частых источников UB в прикладном C++.Please open Telegram to view this post
VIEW IN TELEGRAM
❤14👍5🔥5
Git помогает не терять контроль над кодом, когда ты правишь файлы и параллельно работаешь с командой.
Сначала изменения живут прямо в проекте, потом ты аккуратно откладываешь нужное в “корзинку для коммита”, фиксируешь результат в истории, а уже после этого отправляешь всё на удалённый репозиторий, например на GitHub.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤17👍7🔥4
Почему “всё работало”, а после push_back внезапно упало?
Потому что
После этого все указатели, ссылки и итераторы на элементы становятся недействительными. Вот почему:
Правильно — не хранить адреса элементов
Если очень нужно, то сначала фиксируй ёмкость:
🔥 Правило: любое изменение размера
📣 C++ Ready | #совет
Потому что
push_back может вызвать перевыделение памяти (realloc).vector хранит элементы в непрерывном блоке. Когда места не хватает, он выделяет новый блок, переносит элементы и освобождает старый.После этого все указатели, ссылки и итераторы на элементы становятся недействительными. Вот почему:
int* p = &v[0];
v.push_back(4);
p может начать указывать в освобождённую память. В Debug часто “повезёт”, а в Release ты получишь мусор или падение. Это UB.Правильно — не хранить адреса элементов
vector, если контейнер может расти.Если очень нужно, то сначала фиксируй ёмкость:
v.reserve(100); // гарантируем место
int* p = &v[0];
v.push_back(4); // пока capacity хватает — адреса стабильны
vector может инвалидировать всё, что указывает внутрь. reserve() спасает, но только пока хватает capacity.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21👍10❤4
Когда список вариантов известен заранее,
std::variant часто дает более прозрачный код, потому что все случаи перечислены явно и проверяются на этапе компиляции.В этом гайде:
• Сравним подход через virtual и подход через std::variant, чтобы увидеть разницу в модели;
• Разберем std::visit на простом примере вычисления площади;
• Покажем, как добавление нового типа сразу подсвечивает необработанные места.
Освоив эту технику, вы сможете выбирать между runtime и compile-time полиморфизмом осознанно и без лишней сложности.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥24👍9❤7