tgindex
C++ geek

Учим C/C++ на примерах

Последний пост
07:21
Последнее чтение
16:50
Постов за неделю
2
Всего постов
38
Тип
открытый
Язык
русский
Категория
Технологии (по похожим)
В каталоге с
13 авг.
Подписчики
3 557
−5 за 4 дн.
Сутки
−1
−0,03%
Неделя
 
Месяц
 
Просмотров на пост
648
37 постов
Вовлечённость
18,2%
к подписчикам
Постов в день
0,3
всего 38
Упоминаний
3
каналов
Охват размещения
оценка
1/24сутки в ленте
385
1/48двое суток
441
1/72трое суток
475

Оценка по просмотрам недавних постов: пост набирает почти всё за первые сутки.

Посты

  • 07:2121921

    Зачем [[nodiscard]] и когда он реально спасает? Сколько раз вы видели: функция возвращает значение, а кто-то его тупо игнорирует. А потом баги из ниоткуда. В C++17 завезли [[nodiscard]], и это реально полезная штука. [[nodiscard]] int compute() { return 42; } int main() { compute(); // warning: ignoring return value } Компилятор предупреждает: "эй, ты вызвал, но не используешь результат". Где это особенно важно: - Функции, которые возвращают ошибки (std::error_code, std::optional, bool успеха операции); - Функции, где пропуск результата ломает логику (например, RAII-объекты, токены отмены, хендлы). Можно навесить [[nodiscard]] и на типы (C++20): struct [[nodiscard]] Result { bool ok; }; Result foo(); foo(); // warning! Вместо неочевидных багов — раннее предупреждение компилятора. ⚡ Лайфхак: Если компилятор слишком шумит — можно сделать [[nodiscard("объяснение")]] (C++20), чтобы явно подсказать, зачем это. Вывод: ставьте [[nodiscard]] на всё, что нельзя безнаказанно проигнорировать. Это дешёвая страховка от глупых багов. 📲 Мы в MAX ➡️ @cpp_geek

  • Почему std::vector<bool> — это ловушка Если вы думаете, что std::vector<bool> — обычный вектор, только для bool, то… сюрприз! Это не совсем так. Чтобы экономить память, стандартная библиотека делает его специализацией, хранящей биты упакованно. Цена — нетипичное поведение: std::vector<bool> v{true, false, true}; bool* p = &v[0]; // Ошибка! Тут нет обычного bool* Элементы vector<bool> — это не настоящие bool, а прокси-объекты. Они ведут себя как bool, но фактически это обёртки над битами. Итог: - нельзя получить указатель на элемент; - работа с ними медленнее, чем с bool; - поведение иногда ломает шаблонный код, который ожидает нормальные ссылки и указатели. Что делать? Если вам нужна коллекция булей — берите std::vector<char> или std::vector<uint8_t>. Памяти уйдёт чуть больше, но всё будет предсказуемо и быстро. std::vector<bool> стоит использовать только если критична экономия памяти, и вы понимаете все его подводные камни. 📲 Мы в MAX ➡️ @cpp_geek

  • RAII — твой лучший друг (и почему не стоит бояться умных указателей) Старый добрый new / delete — это классика, но и источник утечек, крашей и боли. В современном C++ ручное управление памятью почти всегда антипаттерн. Решение — RAII (Resource Acquisition Is Initialization): ресурсы живут ровно столько, сколько объект, который ими владеет. Ушёл объект из области видимости — ресурс освободился. Пример с умными указателями: #include <memory> #include <iostream> struct Foo { Foo() { std::cout << "Init\n"; } ~Foo() { std::cout << "Destroy\n"; } }; void bar() { std::unique_ptr<Foo> p = std::make_unique<Foo>(); // RAII // делаем что-то } // тут автоматически вызовется ~Foo() Что важно знать: * std::unique_ptr — владение в единственном числе, идеально для большинства случаев. * std::shared_ptr — разделённое владение (но дороже по производительности). * Никогда не делай new без обёртки — почти всегда лучше std::make_unique или std::make_shared. RAII работает не только для памяти: файлы, мьютексы, сокеты — всё. Достаточно обернуть ресурс в класс с деструктором. Профит: меньше багов, меньше утечек, чище код. 📲 Мы в MAX ➡️ @cpp_geek

  • 🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. https://max.ru/tipsysdmin Типичный Сисадмин https://max.ru/channel_win_sysadmin Системный Администратор Windows https://max.ru/channel_linux_admin Linux: Системный администратор https://max.ru/channel_linuxmod Linux https://max.ru/channel_i_linux Системный администратор https://max.ru/channel_devopslib DevOps, SRE, Sysadmin https://max.ru/channel_devops_star DevOps Star (Звезда Девопса) Excel лайфхак 📌 https://t.me/Excel_lifehack Excel лайфхак Английский с нуля 🇬🇧 https://max.ru/UchuEnglish 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С https://max.ru/channel_DevLab1C 1С:Предприятие 8 Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика https://max.ru/channel_cpp_geek C++ geek Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Rust📌 https://max.ru/channel_rust_lib Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика https://max.ru/channel_java_geek Java Geek GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии в IT📌 https://max.ru/progjob https://max.ru/channel_rabotait Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Городские📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП https://max.ru/channel_krasnodar_novosty Краснодар Новости https://max.ru/channel_novosibirsk_novosti Новосибирск https://max.ru/channel_samara_novosti Новости Самары https://max.ru/channel_ekaterinburg_novosti Новости Екатеринбурга https://max.ru/channel_kazan_novosti Новости Казани https://max.ru/channel_omsk_novosti Новости Омска https://max.ru/channel_moskva_24 Москва 24

  • Move-семантика: где можно ловко сэкономить Многие знают про std::move, но не всегда используют его там, где это реально ускоряет код. Простой пример — возврат локального объекта из функции: #include <string> std::string make_string() { std::string s = "Hello"; return s; // RVO или move } С C++17 тут почти всегда RVO (Return Value Optimization). Но если RVO невозможен (например, возвращаем тернарный оператор), компилятор применит move: std::string make_string(bool flag) { std::string a = "foo", b = "bar"; return flag ? a : b; // тут будет move } А вот так можно подсказать компилятору явно: return std::move(flag ? a : b); Но осторожно: не делайте std::move для локальной переменной в простом return — это может сломать RVO и привести к лишнему перемещению. Ещё полезно помнить: move не всегда бесплатный. Например, для std::vector он копирует указатель и размер, но не элементы. Для std::string — зависит от Small String Optimization: короткие строки перемещаются как копия. Вывод: используйте std::move там, где явно хотите отдать объект, а не копировать. Но не злоупотребляйте им: компилятор с C++17 сам неплохо справляется. 📲 Мы в MAX ➡️ @cpp_geek

  • Зачем std::move от std::string в emplace_back? Кажется, emplace_back(std::move(str)) — избыточно: ведь emplace_back сам конструирует объект на месте. Но с std::string и другими перемещаемыми типами всё не так просто. Пример: std::vector<std::string> vec; std::string str = "hello"; vec.emplace_back(str); // копия vec.emplace_back(std::move(str)); // перемещение Почему? Потому что: > emplace_back вызывает конструктор std::string(const std::string&), если аргумент — const std::string&, > и std::string(std::string&&), если аргумент — std::string&&. А str — это lvalue. Даже внутри emplace_back. Без std::move, ты просишь вектор скопировать строку. С std::move — переместить. Это относится ко всем emplace_*, когда ты передаёшь существующий объект. emplace_back("hello") — другое дело: тут создаётся временный const char*, и он уже используется для конструктора string. 👉 Правило: если аргумент — перемещаемый объект (например, std::string, std::vector), и ты передаёшь его в emplace_*, не забывай std::move. Иначе будет лишняя копия. 📲 Мы в MAX ➡️ @cpp_geek

  • Что такое ADL и как она может вас подставить Argument-Dependent Lookup (ADL) — это фича, которая может как упростить код, так и привести к сюрпризам. Представьте: namespace math { struct Vec {}; void print(const Vec&) { std::cout << "Vec\n"; } } void foo() { math::Vec v; print(v); // компилятор найдёт math::print через ADL! } Хотя print не в текущем скоупе, компилятор ищет её в namespace аргумента v, т.е. math. Это и есть ADL. Звучит удобно. Но... ⚠️ Опасность: namespace lib { struct Widget {}; void process(const Widget&) { std::cout << "lib::process\n"; } } void process(int) { std::cout << "global::process\n"; } void bar() { lib::Widget w; process(w); // вызовет lib::process, а не global::process! } Такой вызов может внезапно потянуть неожиданные функции, особенно в generic-коде (например, в шаблонах), где ADL может найти «лишнее». ✅ Best practices: * Не полагайся на ADL без крайней нужды. * Используй ::qualified::names для ясности. * В шаблонах — лучше явно передавать функции (через policy, traits, или параметры шаблона). 📲 Мы в MAX ➡️ @cpp_geek

  • std::thread std::thread является частью стандартной библиотеки C++ и предоставляет возможность создания и управления потоками выполнения. Он позволяет запускать функции в отдельных потоках, обеспечивая параллельное выполнение кода. Обратите внимание, что после создания потока std::thread, вы должны вызвать join() или detach() для корректной обработки завершения потока. В приведенном примере мы использовали join(), чтобы основной поток дождался завершения потока t1. Если вы вызываете join() после завершения потока, программа может выдать исключение или вызвать неопределенное поведение. 📲 Мы в MAX ➡️ @cpp_geek

  • Полезные функции, которые будут полезны продвинутым C++ разработчикам. 1. void assert_or_throw(bool cond, const std::string& msg) Универсальная замена assert в runtime-среде: void assert_or_throw(bool cond, const std::string& msg) { if (!cond) throw std::runtime_error(msg); } 2. template<typename T> std::string to_string_precise(const T& val, int precision = 6) Преобразование чисел с точностью: template<typename T> std::string to_string_precise(const T& val, int precision = 6) { std::ostringstream out; out << std::fixed << std::setprecision(precision) << val; return out.str(); } 3. template<typename F> auto scope_exit(F&& f) RAII-функция для отложенного вызова: template<typename F> class ScopeExit { F func; bool active = true; public: ScopeExit(F&& f) : func(std::forward<F>(f)) {} ~ScopeExit() { if (active) func(); } void dismiss() { active = false; } }; template<typename F> ScopeExit<F> scope_exit(F&& f) { return ScopeExit<F>(std::forward<F>(f)); } 4. template<typename T> constexpr bool is_power_of_two(T x) Компилируемая проверка степени двойки: template<typename T> constexpr bool is_power_of_two(T x) { return x > 0 && (x & (x - 1)) == 0; } 5. template<typename T> void hash_combine(std::size_t& seed, const T& val) Для реализации собственного std::hash: template<typename T> void hash_combine(std::size_t& seed, const T& val) { seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } 6. std::vector<std::string> split(const std::string& str, char delimiter) Полезна для парсинга CSV, логов и т.д.: std::vector<std::string> split(const std::string& str, char delimiter) { std::vector<std::string> out; std::istringstream ss(str); std::string token; while (std::getline(ss, token, delimiter)) { out.push_back(token); } return out; } 7. template<typename T> T clamp(T val, T min_val, T max_val) Ручной аналог std::clamp (если нужна совместимость со старым C++): template<typename T> T clamp(T val, T min_val, T max_val) { return std::max(min_val, std::min(val, max_val)); } 8. template<typename Container, typename Predicate> bool any_of(const Container& c, Predicate pred) Упрощённая обёртка над std::any_of: template<typename Container, typename Predicate> bool any_of(const Container& c, Predicate pred) { return std::any_of(c.begin(), c.end(), pred); } 9. template<typename... Args> std::string format(const std::string& fmt, Args&&... args) Интерфейс к std::format (C++20+): template<typename... Args> std::string format(const std::string& fmt, Args&&... args) { return std::vformat(fmt, std::make_format_args(args...)); } 10. template<typename T> std::string type_name() Получение имени типа на этапе компиляции: template<typename T> std::string type_name() { #ifdef __clang__ std::string name = __PRETTY_FUNCTION__; return name.substr(31, name.length() - 32); #elif defined(__GNUC__) std::string name = __PRETTY_FUNCTION__; return name.substr(49, name.length() - 50); #elif defined(_MSC_VER) std::string name = __FUNCSIG__; return name.substr(38, name.length() - 45); #else return "unknown"; #endif } 📲 Мы в MAX ➡️ @cpp_geek

  • 🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. https://max.ru/tipsysdmin Типичный Сисадмин https://max.ru/channel_win_sysadmin Системный Администратор Windows https://max.ru/channel_linux_admin Linux: Системный администратор https://max.ru/channel_linuxmod Linux https://max.ru/channel_i_linux Системный администратор https://max.ru/channel_devopslib DevOps, SRE, Sysadmin https://max.ru/channel_devops_star DevOps Star (Звезда Девопса) Excel лайфхак 📌 https://t.me/Excel_lifehack Excel лайфхак Английский с нуля 🇬🇧 https://max.ru/UchuEnglish 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С https://max.ru/channel_DevLab1C 1С:Предприятие 8 Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика https://max.ru/channel_cpp_geek C++ geek Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Rust📌 https://max.ru/channel_rust_lib Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика https://max.ru/channel_java_geek Java Geek GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии в IT📌 https://max.ru/progjob https://max.ru/channel_rabotait Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Бонус 📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП

  • 🧵 Сегодня покажу вам простой способ логгировать вызовы функций в C++ — пригодится для отладки и анализа кода. Часто бывает нужно понять, какие функции вызываются, в каком порядке и с какими параметрами. Вручную вставлять std::cout — неудобно. Вместо этого используем RAII-макрос с выводом в консоль: #include <iostream> #include <string> struct FunctionLogger { std::string func_name; FunctionLogger(const std::string& name) : func_name(name) { std::cout << ">> Entering: " << func_name << '\n'; } ~FunctionLogger() { std::cout << "<< Exiting: " << func_name << '\n'; } }; #define LOG_FUNCTION() FunctionLogger logger(__FUNCTION__) Теперь в любой функции достаточно просто написать LOG_FUNCTION();, и вы получите автоматический лог при входе и выходе: void do_work() { LOG_FUNCTION(); // Работаем... } Это особенно удобно в больших проектах, когда нужно быстро локализовать ошибку или понять структуру вызовов. Можно доработать: лог в файл, потокобезопасность, включение по флагу компиляции и т.д. 📲 Мы в MAX ➡️ @cpp_geek

  • Невидимый UB: возвращаем ссылку на локальную переменную Одна из самых коварных ошибок в C++ — возврат ссылки на переменную, срок жизни которой закончился. Казалось бы, всё компилируется, запускается... и даже иногда "работает". А под капотом — undefined behavior. Пример: const std::string& getName() { std::string name = "John"; return name; // 💥 Возвращаем ссылку на локальный объект } Функция возвращает ссылку на name, но как только getName() завершится, name уничтожается. Ссылка указывает в никуда. Использование этой ссылки: std::cout << getName() << "\n"; // UB: может напечатать мусор, может упасть 👀 Хитрость: такая ошибка часто прячется внутри более сложных функций, и ловится не сразу. Особенно в шаблонном коде или при рефакторинге. 🔒 Как безопасно? * Возвращайте по значению, если объект небольшой или RVO (return value optimization) работает: std::string getName() { std::string name = "John"; return name; // ок, RVO устранит копирование } * Или передавайте результат через параметр: void getName(std::string& out) { out = "John"; } 💡 Профит: избежите UB, багов-призраков и бессонных ночей. 📲 Мы в MAX ➡️ @cpp_geek

  • Тема: Почему std::vector<bool> - не совсем std::vector На первый взгляд std::vector<bool> — обычный вектор, только из булевых значений. Но это особенный шаблон. Вместо хранения bool как полноценного байта, он упаковывает их в биты. Экономит память? Да. Но есть нюансы. Пример: std::vector<bool> flags = {true, false, true}; auto x = flags[0]; // Не bool, а прокси-объект! bool y = flags[0]; // OK — копия значения bool& z = flags[0]; // Ошибка компиляции flags[0] возвращает proxy-объект, а не bool&, потому что нельзя вернуть ссылку на бит. Из-за этого: * Нельзя взять адрес элемента * Нельзя использовать std::vector<bool> с API, ожидающим bool* или bool& * Некоторые шаблоны не работают (особенно в generic-коде) Хочешь экономии — будь готов к сюрпризам. Хочешь предсказуемости — используй std::deque<bool> или std::vector<char>. ⚠️ Кстати, std::vector<bool> — единственная специализация STL-контейнера в стандартной библиотеке. ➡️ @cpp_geek

  • Ключевые библиотеки Boost, которые полезно знать каждому C++ разработчику Вот топ-5 библиотек Boost: 1️⃣ Boost.Asio Асинхронный ввод-вывод и сетевое программирование. Незаменим для серверных приложений. 2️⃣ Boost.Beast HTTP и WebSocket клиенты/серверы. Построен на Asio. 3️⃣ Boost.Serialization Сериализация сложных структур данных в потоки байтов и обратно. 4️⃣ Boost.Graph Алгоритмы на графах: поиск путей, обходы, топологическая сортировка и др. 5️⃣ Boost.Spirit Создание парсеров прямо в коде C++ без внешних генераторов. ➡️ @cpp_geek

  • Зачем [[nodiscard]] нужен не только для возврата значения Если ты думаешь, что [[nodiscard]] — это просто защита от игнора Result, то вот фокус: его можно вешать и на классы, и на функции, и даже на enum — и это реально помогает избежать багов. Пример: struct [[nodiscard]] Error { std::string message; }; Error do_something() { return {"Что-то пошло не так"}; } void foo() { do_something(); // warning: ignoring return value of nodiscard type } А теперь магия с методами: struct Connection { [[nodiscard]] bool is_valid() const { return valid_; } private: bool valid_ = false; }; void check_connection(const Connection& conn) { conn.is_valid(); // warning: result of 'is_valid' is unused } 📌 Даже если функция возвращает bool — компилятор предупредит, если ты его проигнорируешь. Это круто, когда метод что-то проверяет, ищет или сигналит об ошибке — и ты точно не хочешь забыть проверить результат. ⚠️ Но аккуратно: [[nodiscard]] не бросает исключения и не делает функцию безопасной. Это подсказка компилятору и твой напарник по коду. Если хочешь писать более надёжный и самодокументируемый код — юзай [[nodiscard]] не только по дефолту, а осознанно. ➡️ @cpp_geek

  • Сейчас покажу вам простой, но очень полезный приём, как аккуратно и безопасно управлять ресурсами в C++ с помощью RAII (Resource Acquisition Is Initialization). Когда вы работаете с ресурсами (файлы, сокеты, мьютексы и т.д.), важно не забывать освобождать их. Особенно если программа может завершиться по исключению. И вот тут RAII — наш лучший друг. Рассмотрим пример: #include <fstream> #include <string> void writeToFile(const std::string& filename, const std::string& data) { std::ofstream file(filename); if (!file) { throw std::runtime_error("Unable to open file"); } file << data; } // файл автоматически закрывается здесь Мы открыли файл — и не закрыли его вручную! Почему? Потому что std::ofstream сам закроет его в своём деструкторе. Это и есть RAII в действии. И теперь представьте: вы можете создавать свои классы с таким же поведением! Например, класс-обёртку над pthread_mutex_t или системным дескриптором. RAII — это стиль. И это стиль надёжного кода. ➡️ @cpp_geek

  • Тема: std::optional и return value optimization (RVO) Когда возвращаешь из функции std::optional<T>, часто задумываешься о лишних копиях. Например, вот так: std::optional<std::string> make_name(bool valid) { if (valid) return "Женя"; return std::nullopt; } Миф: здесь всегда будет копирование строки. Реальность: современные компиляторы отлично оптимизируют этот код благодаря RVO (Return Value Optimization). Если возвращаемое значение — временный объект, C++ может создать его сразу в том месте, куда он должен быть возвращён. Копий не будет! Ещё интереснее с C++17: возвращение {} для std::optional<T> и "str" для строки — это всё равно RVO. ⚠️ Но если возвращаешь существующий объект: std::optional<std::string> wrap(const std::string& s) { return s; // здесь копия неизбежна } - тут RVO не поможет, потому что возвращаешь уже существующий объект, а не временный. Вывод: Не бойся возвращать большие объекты через std::optional! RVO спасает производительность, когда возвращаешь временные объекты. ➡️ @cpp_geek

  • 👨‍💻На работе код читают чаще, чем пишут. Когда смысл приходится восстанавливать по комментариям, неочевидным параметрам и скрытым договорённостям, команда теряет время, а риск ошибок растёт. 📆16 июля в 20:00 МСК на открытом уроке разберем, как переносить смысл программы в типы, сигнатуры и структуру кода. На примерах из реальных проектов участники сделают сигнатуры понятнее с помощью std::optional и enum class, упростят управление ресурсами через RAII и заменят сложные циклы готовыми алгоритмами, ranges и views. В результате у вас появится набор приёмов для более ясного и самодокументируемого кода. 🏁Урок проходит в преддверии старта курса «C++-разработчик». Зарегистрируйтесь, чтобы познакомиться с форматом обучения, задать вопросы эксперту и потренироваться выражать намерения средствами языка, а не комментариями: https://vk.cc/cZliRl Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

  • Пару фишек про шаблоны, которые могут спасти час дебага: 1. CTAD (Class Template Argument Deduction, C++17) Не надо вручную указывать аргументы: std::pair p(42, 3.14); // вместо std::pair<int, double> p(42, 3.14); std::vector v = {1,2,3}; // компилятор сам выведет std::vector<int> Помогает сократить код и избежать опечаток. 2. Fold-выражения (C++17) для арг-паков: auto sum = [](auto... args){ return (args + ...); // ((a + b) + c) + ... }; std::cout << sum(1,2,3,4); // 10 Позволяют писать операции над любым числом параметров без рекурсии. 3. SFINAE → Concepts (C++20) Старый стиль через enable_if легко сломать: template<class T> std::enable_if_t<std::is_integral_v<T>, T> foo(T x) { return x*2; } С Concepts чище и понятнее: template<std::integral T> T foo(T x) { return x*2; } 4. CRTP (Static polymorphism) Быстрее виртуалок и без RTTI: template<class D> struct Base { void interface() { static_cast<D*>(this)->impl(); } }; struct Derived : Base<Derived> { void impl() { std::cout<<"OK\n"; } }; Шаблоны — это не только про универсальность, но и про ясность кода. Освой тонкости, и они станут 🔧, а не головняком. ➡️ @cpp_geek

  • Тонкости STL, которые часто вылетают в продакшн: 1. Инвалидирование итераторов При vector::erase все итераторы от позиции удаления до end() становятся «битые». Чтобы безопасно отфильтровать и удалить элементы, пользуйтесь erase–remove идиомой: auto it = std::remove_if(v.begin(), v.end(), [](int x){ return x < 0; }); v.erase(it, v.end()); remove_if сдвигает «хвост» вперёд, но не меняет размер контейнера. 2. reserve vs resize * v.reserve(n) выделяет память, но не создаёт объектов → size() не меняется, можно безопасно push_back. * v.resize(n) создаёт n элементов, инициализированных значениями по умолчанию. 3. Производительность std::distance На random-access итераторах (например, vector) это O(1), а на bidirectional или forward (например, list) — O(n). Для списков используйте size() (C++11+) или считайте вручную в критичных местах. 4. emplace_back vs push_back При сложных типах emplace_back может избежать лишнего копирования: v.emplace_back(ctor_arg1, ctor_arg2); // vs v.push_back(MyType(ctor_arg1, ctor_arg2)); 5. Памятка про компараторы В set или map ваш компаратор должен задавать строгий-уровень-менее (operator<): если comp(a,b)==true, то comp(b,a) обязан быть false. Иначе — UB. Быстро, без воды, но с пользой — проверяйте эти моменты в своём коде! ➡️ @cpp_geek