C/C++ Ready | Программирование
14.9K subscribers
1.24K photos
69 videos
566 links
Авторский канал по разработке на C и C++.
Ресурсы, гайды, задачи, шпаргалки.
Информация ежедневно пополняется!

Автор: @energy_it

РКН: https://clck.ru/3QREHc

Реклама на бирже: https://telega.in/c/cpp_ready
Download Telegram
📂 Шпаргалка по std::span в C++20!

На картинке — аккуратная “Span Cheat Sheet”, которая показывает, как работать с std::span: лёгким и не владеющим памятью представлением непрерывной последовательности объектов.

Показано, как создавать span из вектора или массива, как получать элементы, размер, поддиапазоны и почему span особенно удобен в параметрах функций.

Сохрани, чтобы больше не путаться с указателями и массивами

📣 C++ Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🔥74
Как добавить “поле-настройку” в struct и не раздувать память?

Иногда хочется хранить рядом с данными “маркер/политику/стратегию”, но сам тип пустой. В обычном виде даже пустой член класса вроде Tag tag; может занимать место — компилятор часто обязан обеспечивать уникальность адресов и соблюдать выравнивание.

В C++20 есть атрибут [[no_unique_address]], который разрешает компилятору не выделять отдельную память под пустой член.

Сравни:
было: struct A { int value; Tag tag; };
стало: struct B { int value; [[no_unique_address]] Tag tag; };

Это видно через измерение размера:
std::cout << sizeof(A);
std::cout << sizeof(B);

Во многих ABI B будет меньше (или не больше), потому что Tag может “слиться” с уже существующим адресом внутри объекта.

🔥 Это оптимизация, а не гарантия. И ещё нюанс: у поля вроде [[no_unique_address]] Tag tag; адрес &obj.tag может совпасть с &obj, так что не полагайся на уникальность адреса.

📣 C++ Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍6🔥4🤝1
Поговорим про std::ssize: размер контейнера со знаком — без кастов и ловушек size_t!

Полезно в обратных циклах и сравнениях индексов, где size_t легко ломает логику.
std::vector<int> v{10, 20, 30};

for (int i = std::ssize(v) - 1; i >= 0; --i) {
std::cout << v[i] << ' ';
}


Почему так? Потому что v.size() возвращает size_t, а это беззнаковый тип. Из-за этого даже простые проверки и “обратные” циклы легко превращаются в ловушки: компилятор ругается на сравнение знакового и беззнакового, а иногда логика вообще ломается.

Классическая проблема выглядит так:
for (size_t i = v.size() - 1; i >= 0; --i) {
std::cout << v[i] << ' ';
}


Условие i >= 0 для size_t всегда истинно, и цикл может уйти в бесконечность, потому что i никогда не станет “меньше нуля”, он просто переполнится.

std::ssize(v) решает это правильно и без кастов. Он возвращает размер контейнера, но уже в знаковом типе, поэтому выражения вроде
std::ssize(v) - 1


и проверки i >= 0 ведут себя ожидаемо, а предупреждения компилятора исчезают.

🔥 std::ssize — маленькая привычка, которая убирает целый класс багов вокруг size_t, особенно в циклах и сравнениях индексов.

📣 C++ Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
20👍7🔥4
☕️ Отличная статья — про то, как сделать многопоточность в HTTP-сервере без потока на каждого клиента!

В этой статье:
• Поймёшь, почему «один клиент — один поток» плохо
• Соберёшь ThreadPool: очередь задач, воркеры, синхронизация без лишних аллокаций
• Построишь конечный автомат: состояния, хендлеры, переходы для HTTP-клиента

🔊 Продолжай читать на Habr!


📣 C++ Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
8👍3🔥3
👩‍💻 Разбираем scope_exit: “finally” для C++ без макросов и лишних классов!

Когда в функции несколько return, а ещё возможны исключения — легко забыть закрыть файл, откатить флаг или завершить “временный режим”. scope_exit решает это просто: задаёшь действие один раз — и оно гарантированно выполнится при выходе из блока.

В этом посте:

Поймём, как работает scope_exit и почему он похож на defer/finally;

Разберём базовый шаблон “ресурс + уборка рядом” на коротких примерах;

Посмотрим реальный кейс: мини-профайлер и автоматический rollback.


Освоив scope_exit, вы сможете делать cleanup в одном месте, не размазывая его по коду, и спокойно добавлять новые выходы из функции без риска “забыть убрать”.

📣 C++ Ready | #гайд
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥189👍6
Почему после placement new “старый указатель” может начать врать?

В низкоуровневом коде иногда создают объект прямо в заранее выделенной памяти: S* p = new (storage) S(1);. Это placement new — объект живёт в буфере, а не в куче.

Проблема начинается, когда ты вручную заканчиваешь жизнь объекта и создаёшь новый в той же памяти:
p->~S();

и сразу после этого:
new (storage) S(2);

Логически кажется: “адрес тот же, значит p снова указывает на актуальный объект”. Но по правилам C++ это уже другой объект с новой lifetime, и компилятор имеет право оптимизировать так, будто через p ты всё ещё обращаешься к старому (особенно в сложных сценариях внутри шаблонов/контейнеров).

std::launder (C++17) — это способ “перепривязать” указатель к новому объекту и дать компилятору понять, что в этой памяти теперь другая сущность:
S* q = std::launder(p);

После этого чтение через q->x считается корректным и не ломается оптимизациями.

🔥 Если у тебя обычный прикладной код без ручного управления временем жизни объектов — скорее всего он тебе никогда не понадобится.

📣 C++ Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍8🔥4
This media is not supported in your browser
VIEW IN TELEGRAM
☕️ Clang-Tidy — “линтер” для C++ на базе Clang с автофиксом проблем!

Официальная документация Extra Clang Tools: clang-tidy помогает находить и исправлять типичные ошибки в коде — от нарушений стиля и misuse интерфейсов до багов, которые можно вывести статическим анализом.

📌 Оставляю ссылочку: clang-tidy

📣 C++ Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥104👍4
std::byte: честные “сырые байты” вместо char/uint8_t!

Он помогает не путать бинарные данные с текстом и не ловить случайную арифметику над “байтами”.

Часто под байты берут uint8_t или char:
void send(const std::vector<uint8_t>& data);

int main() {
std::vector<uint8_t> buf = {0x48, 0x65, 0x6C, 0x6C, 0x6F};
send(buf);
}


Проблема в том, что такие типы легко начинают жить как “маленькие числа” или “символы”: кто-то делает buf[i] + 1, кто-то печатает как текст, и смысл буфера расползается.

В C++17 для этого есть std::byte — отдельный тип именно для бинарщины.
С ним нельзя случайно делать арифметику, зато можно явно делать побитовые операции.

Как хранить и передавать байты:
void send(std::span<const std::byte> data);

int main() {
std::vector<std::byte> buf = {
std::byte{0x48}, std::byte{0x65}, std::byte{0x6C},
std::byte{0x6C}, std::byte{0x6F}
};
send(buf);
}


Если нужно получить число — делай это явно:
#include <bit>
std::byte b{0xFF};
int x = std::to_integer<int>(b);


🔥 std::byte делает работу с бинарными данными ясной: меньше неявных превращений, меньше путаницы “текст vs байты”, больше контроля.

📣 C++ Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥175👍4👎1
🔥41👍108😁4
Что же выведет консоль?
Anonymous Quiz
20%
A
51%
B
23%
C
6%
D
👍115🔥3
📂 Шпаргалка по IP-адресам!

Например, 192.168.x.x — для домашней сети, а 10.x.x.x — для крупных корпоративных систем. CIDR (/24, /16, /8) — помогает точно задать размер подсети и количество хостов.

На картинке — всё, что нужно знать про IP: диапазоны, маски, специальные адреса, публичные DNS и основы IPv6.

Сохрани, чтобы не забыть!

📣 C++ Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
27👍9🔥8
Почему vector{10, 1} и vector(10, 1) — это разные контейнеры?

На вид разница “всего лишь в скобках”, но смысл радикально меняется.

Круглые скобки выбирают конструктор “размер + значение”, то есть создают 10 элементов со значением 1:
std::vector<int> a(10, 1);


А фигурные скобки в первую очередь пытаются попасть в конструктор с std::initializer_list, который трактует аргументы как список элементов. Поэтому тут создаётся вектор из двух элементов: 10 и 1:
std::vector<int> b{10, 1};


Это ловушка потому, что initializer_list при наличии часто “побеждает” другие перегрузки — и ты получаешь не тот контейнер, который ожидал.

🔥 Если ты хочешь “N одинаковых элементов” — используй (n, value). Если хочешь “конкретные элементы” — используй {...}

📣 C++ Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21👍98🤝1
🧐 Шпаргалка по std::string_view!

На картинке — компактная памятка по std::string_view: что это лёгкий, не владеющий памятью и read-only “вид” на строку/массив символов, как его удобно передавать в функции без лишних копий, и какие методы чаще всего используются

Отдельно подсвечены важные моменты: string_view отлично подходит для подстрок и диапазонов без копирования, но нужно следить за временем жизни исходной строки — view может “пережить” данные и стать висячим.

📣 C++ Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
13👍5🔥5