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::string под контролем!

В этой шпаргалке — короткие приёмы, которые делают работу со строками быстрее и безопаснее: как заранее готовить память, удобно склеивать и резать строки, быстро искать подстроки и корректно отдавать данные в C-API без неприятных сюрпризов.

📣 C++ Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🤝32🔥185👍1
👍 Отличная статья — про RAII как про дизайн-инструмент, а не только про “освободить ресурс”

В этой статье:
• Понять, как RAII помогает строить архитектуру и инварианты
• Увидеть примеры управления разными ресурсами (не только памятью)
• Научиться делать код устойчивым к исключениям и “утечкам ответственности”

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


📣 C++ Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍65😁1
Безопасный “побитовый каст” без UB — std::bit_cast!

Иногда нужно посмотреть на биты значения: получить IEEE754-представление float, собрать/разобрать сетевой пакет, сделать хеш по битам, интерпретировать double как uint64_t.

Многие делают это через reinterpret_cast или “указательную магию” — и ловят UB из-за strict aliasing и выравнивания.

Сначала типичный “ручной” (опасный) вариант:
float f = 1.0f;
auto u = *reinterpret_cast<std::uint32_t*>(&f); // UB!
use(u);


Теперь то же самое правильно одной строкой: std::bit_cast (C++20) копирует биты между типами одинакового размера:
float f = 1.0f;
auto u = std::bit_cast<std::uint32_t>(f);
use(u);


Частый практический кейс — быстро проверить знак/экспоненту float без математики:
bool is_negative(float x) {
auto bits = std::bit_cast<std::uint32_t>(x);
return (bits >> 31) != 0;
}


Ещё один популярный пример — получить “сырой” uint64_t из double для стабильного сравнения/логирования битов:
std::uint64_t raw_bits(double d) {
return std::bit_cast<std::uint64_t>(d);
}


И обратная операция — восстановить значение из битов (тоже безопасно, если размер совпадает):
double from_bits(std::uint64_t bits) {
return std::bit_cast<double>(bits);
}


🔥 std::bit_cast делает намерение явным: “мне нужны биты, а не преобразование значения” — без reinterpret_cast, без строгого алиасинга, меньше шансов поймать UB.

📣 C++ Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
14🔥9👍5
This media is not supported in your browser
VIEW IN TELEGRAM
❤️ USACO Guide — роадмап по олимпиадному программированию!

Бесплатный “one-stop shop” для подготовки к USACO: структурированные разделы от Intro и Bronze до Platinum/Advanced, где в каждом модуле есть объяснение темы, советы по реализации, подборка задач для практики и разборы/редакции

📌 Оставляю ссылочку: usaco.guide

📣 C++ Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
12👍8🔥5🤝1
Почему std::move не “перемещает”?

Многие думают, что std::move(x) физически “переносит” данные и очищает x. Но std::move ничего не двигает — это всего лишь приведение к rvalue-ссылке, то есть сигнал компилятору: “этот объект можно перемещать”.

Проблема начинается, когда после std::move мы продолжаем пользоваться объектом как раньше:
std::string s = "hello";
std::string a = std::move(s);

std::cout << s; // логическая ошибка


После перемещения объект обязан оставаться валидным, но его состояние становится неопределённымstd::string часто будет пусто, но полагаться на это нельзя). Поэтому любые “проверю что осталось” и “ещё раз использую” — источник багов.

Правильное правило простое:
std::move(x) = “я отказываюсь от значения x
после этого x можно только: присвоить новое значение / уничтожить / вызвать безопасные операции, не зависящие от содержимого.

🔥 Итог: std::move — не перенос, а разрешение на перенос. Если ты пишешь std::move, считай, что “объект дальше мне не нужен” — так код становится предсказуемым и без скрытых сюрпризов.

📣 C++ Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22🔥96🤝2
Антипаттерн: # define DEBUG 1 vs NDEBUG

Часто для отладочного кода делают что-то вроде #define DEBUG 1 и оборачивают всё в #ifdef DEBUG.

Работает? Да.
Надёжно? Не всегда.

Проблема в том, что такой DEBUGне стандартный, и он легко расходится с реальным типом сборки. В итоге можно случайно оставить отладочный код в релизе.

В стандарте C++ уже есть специальный макрос для этого — NDEBUG. Если NDEBUG не определён, значит это debug-сборка. Если NDEBUG определён, значит релиз.

Именно на него завязаны assert и многие стандартные проверки.

Плохой вариант:
#define DEBUG 1

void foo(int x) {
#ifdef DEBUG
std::cout << "x = " << x << "\n";
#endif

work(x);
}


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

Правильный вариант — ориентироваться на NDEBUG:
void foo(int x) {
#ifndef NDEBUG
std::cerr << "x = " << x << "\n";
#endif

work(x);
}


Теперь всё согласовано:
• debug-сборка → логирование и проверки есть
• release (-DNDEBUG) → код полностью вырезается компилятором

Точно так же стоит писать и свои отладочные макросы:
#ifndef NDEBUG
#define DBG_LOG(msg) std::cerr << msg << "\n"
#else
#define DBG_LOG(msg) ((void)0)
#endif


🔥 Использование NDEBUG — это не мелочь, а дисциплина сборки: отладочный код никогда не попадёт в релиз случайно, и всё поведение будет согласовано со стандартными механизмами C++.

📣 C++ Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
22👍12🔥7
👩‍💻 Продолжаем прокачивать std::map!

В этой шпаргалке — практичные приёмы для работы со словарём: как безопасно удалять элементы и чистить контейнер, как вставлять или перезаписывать значения без лишнего кода

📣 C++ Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥22🤝116👍2
📂 Напоминалка по Bash-скобкам!

На картинке — компактная шпаргалка по скобкам в Bash: (), {}, $(), [], [[ ]] — что они делают и чем отличаются (подстановка команд, группировка в текущем shell/подоболочке, массивы, brace expansion, параметрическое расширение, арифметика и проверки условий).

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

📣 C++ Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
13🔥9👍7👎1
push_back vs emplace_back: когда что использовать?

Обе функции добавляют элемент в контейнер, но делают это по-разному.

push_back(...) добавляет уже готовый объект. Если передать lvalue — будет копия, если rvalue — будет перемещение:
v.push_back(s);            // копия
v.push_back(std::move(s)); // move


emplace_back(...) не требует готового объекта — он передаёт аргументы в конструктор элемента и создаёт его *сразу внутри* контейнера:
v.emplace_back(5, 'a'); // string("aaaaa") прямо в vector


Это полезно, когда:

• элемент создаётся “на месте” из нескольких параметров;
• хочется избежать лишнего временного объекта (особенно для тяжёлых типов).

🔥 Важный нюанс: в современном C++ разница часто не драматическая (компилятор умеет оптимизировать временные объекты), так что выбирать стоит по читаемости.

📣 C++ Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1510👍7
👐 Замечательная статья — быстрый чеклист приёмов оптимизации C/C++ для повседневного кода!

В этой статье:

• Поймёшь, какие микроизменения действительно влияют на скорость
• Увидишь примеры про типы, порядок полей, преобразования и “дорогие” операции
• Заберёшь идеи про циклы, ветвления и вызовы, чтобы вычищать лишнее без фанатизма

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


📣 C++ Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
11🔥5👍4😁2
Знали что, многие допускают ошибку при использовании оператора delete?

Сегодня как раз ее разберем. Распространенную ошибку в C++ при работе с операторами delete и delete[], она может привести к сбоям программы и утечкам памяти:

Операторы delete и delete[] предназначены для освобождения памяти, выделенной с помощью new и new[] соответственно. Часто можно столкнуться с ошибками, если перепутать эти операторы:
int* ptr = new int[5];  // Выделили память для массива
delete ptr; // Ошибка! Использован неправильный оператор


Для освобождения памяти, выделенной с помощью new[], нужно использовать delete[].

Правильное использование delete[]:
int* ptr = new int[5];  // Выделили память для массива
delete[] ptr; // Правильно освобождаем память


Другой распространенный случай — удаление одной и той же памяти дважды. Это может привести к неопределенному поведению:
int* ptr = new int[5];
delete[] ptr; // Освободили память
delete[] ptr; // Ошибка: память уже освобождена


Установить указатель в nullptr
После того как память освобождена, всегда обнуляйте указатель:
int* ptr = new int[5];
delete[] ptr;
ptr = nullptr; // Указатель больше не указывает на освобожденную память


🔥 Правильное использование этих операторов — ключ к предотвращению утечек памяти и ошибок в управлении памятью.

Всегда следите за тем, какой тип памяти вы освобождаете, и избегайте двойного удаления.

📣 C++ Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥139
13🔥8👍4👎1😁1
std::span: безопасная альтернатива T* + size!

Очень часто функции принимают «сырые» данные так:
void process(const int* data, std::size_t size);


Это быстро, но небезопасно:
указатель и размер легко рассинхронизировать;
компилятор никак не помогает;
легко выйти за границы и словить UB.

В C++20 для этого есть std::span — лёгкая обёртка над непрерывным диапазоном памяти. std::span не владеет данными, но всегда знает их размер и тип.

Перепишем сигнатуру функции:
#include <span>

void process(std::span<const int> data) {
for (int x : data) {
// безопасный проход по диапазону
work(x);
}
}


Теперь функция принимает единое целое, а не два разрозненных аргумента.

Вызывать её можно почти так же просто:
#include <vector>
#include <array>

int main() {
std::vector<int> v{1, 2, 3};
std::array<int, 3> a{4, 5, 6};
int raw[] = {7, 8, 9};

process(v); // std::vector
process(a); // std::array
process(raw); // C-массив
}


Никаких кастов, никаких размеров вручную — всё выводится автоматически.

Если же нужно изменять данные, достаточно убрать const:
void normalize(std::span<int> data) {
for (int& x : data) {
x = std::max(x, 0);
}
}


🔥 std::span — это zero-overhead приём: он не копирует данные, не замедляет код и при этом резко снижает шанс UB из-за выхода за границы или перепутанных размеров.

📣 C++ Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
17👍13🔥9😁1
This media is not supported in your browser
VIEW IN TELEGRAM
☕️ Awesome-Shell — топовая коллекция утилит, скриптов и приёмов для терминала!

Здесь собраны десятки CLI-инструментов, полезные bash/zsh-скрипты, практичные сниппеты и лайфхаки, которые ускоряют работу. Отличный набор для автоматизации, оптимизации и прокачки навыков работы с командной строкой.

Оставляю ссылочку: GitHub 📱


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