Библиотека C/C++ разработчика | cpp, boost, qt
20.3K subscribers
1.78K photos
47 videos
16 files
3.97K links
Все самое полезное для плюсовика и сишника в одном канале.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/d6cd2932

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/67a5bac324c8ba6dcaa1ad17
加入频道
🚀 std::unreachable в C++23

Компилятор не всегда понимает, что некоторые участки кода недостижимы. std::unreachable() помогает ему генерировать более оптимальный код.


📋 Пошаговое решение:

1️⃣ Подключите заголовок
#include <utility>  // C++23


2️⃣ Используйте в switch без default

enum class Color { RED, GREEN, BLUE };

std::string colorToString(Color c) {
switch(c) {
case Color::RED: return "red";
case Color::GREEN: return "green";
case Color::BLUE: return "blue";
}
std::unreachable(); // Говорим компилятору: сюда не попадём!
}


3️⃣ Применяйте в условных блоках

int divide(int a, int b) {
if (b != 0) {
return a / b;
}

// Логически сюда не должны попасть
handleError(); // Наша обработка
std::unreachable(); // Оптимизация для компилятора
}



⚠️ Частые ошибки:

Неправильно: Использовать когда код действительно достижим
Неправильно: Забывать про обработку ошибок перед unreachable()
Правильно: Использовать только когда логически уверены в недостижимости


🎯 Практический совет:

std::unreachable() - это контракт с компилятором. Если код всё-таки достигнет этой точки, поведение неопределено. Используйте только когда на 100% уверены.


🎯 Альтернатива:

В старых стандартах используйте __builtin_unreachable() (GCC/Clang) или __assume(false) (MSVC).

🐸Библиотека C/C++ разработчика #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥85
✏️ Промпт дня: Создание юнит-тестов для надёжного кода

Юнит-тесты — это автоматизированные тесты, которые проверяют поведение отдельных частей кода в изоляции. Они помогают обнаруживать ошибки на ранней стадии и значительно упрощают поддержку кода в C++.


☀️ Решение с помощью AI

Please write unit tests for [имя файла и модуля] to ensure its proper functioning

[ВСТАВЬТЕ ВАШ КОД ЗДЕСЬ]



🧋 Пример трансформации

До:

class Calculator {
public:
int add(int a, int b) { return a + b; }
int divide(int a, int b) {
if (b == 0) throw std::invalid_argument("Division by zero");
return a / b;
}
};


После:

#include <gtest/gtest.h>

TEST(CalculatorTest, AddPositiveNumbers) {
Calculator calc;
EXPECT_EQ(calc.add(2, 3), 5);
}

TEST(CalculatorTest, DivideByZero) {
Calculator calc;
EXPECT_THROW(calc.divide(10, 0), std::invalid_argument);
}

TEST(CalculatorTest, DivideNormalCase) {
Calculator calc;
EXPECT_EQ(calc.divide(10, 2), 5);
}



✏️ Как часто вы пишете юнит-тесты для своего C++ кода?


🐸Библиотека C/C++ разработчика #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥71👍1
🚀 Мгновенное создание реализаций методов класса

Проблема: 🤔 При разработке классов в C++ приходится сначала объявлять методы в заголовочном файле, а затем вручную создавать их реализации в .cpp файле, что требует времени и может привести к ошибкам.

Решение: 🎯 Автоматическое создание реализаций методов класса в соответствующем .cpp файле.

Комбинации клавиш:

• CLion: Alt+Enter на объявлении → Implement methods
• Visual Studio: Ctrl+. на объявлении → Implement all missing members
• VSCode (с C/C++ расширением): Alt+Shift+I

📝 Процесс в CLion:

• Объявите методы в заголовочном файле
• Нажмите Alt+Enter на имени класса
• Выберите Implement methods
• Выберите методы для реализации и целевой файл
• Все выбранные методы будут автоматически созданы с правильным синтаксисом

💡 Эта функция также позволяет:
• Генерировать стандартные методы (конструкторы, деструкторы, операторы)
• Создать все недостающие реализации методов сразу
• Добавлять реализации в уже существующие файлы

Библиотека C/C++ разработчика #буст
6👍3🙏2
🌲 Концепты в C++

Хотите безопасную сериализацию? Создайте концепт для проверки того, что тип можно сериализовать и десериализовать.


✏️ Создание концепта:

1️⃣ Определите требования к типу
2️⃣ Проверьте наличие методов
3️⃣ Используйте в шаблонах


#include <concepts>
#include <iostream>
#include <string>
#include <sstream>

// Концепт для сериализуемых типов
template<typename T>
concept Serializable = requires(T obj, std::ostream& os, std::istream& is) {
{ obj.serialize(os) } -> std::same_as<void>;
{ T::deserialize(is) } -> std::same_as<T>;
};

// Пример сериализуемого класса
struct Person {
std::string name;
int age;

void serialize(std::ostream& os) const {
os << name << " " << age;
}

static Person deserialize(std::istream& is) {
Person p;
is >> p.name >> p.age;
return p;
}
};

// Функция для работы с сериализуемыми объектами
template<Serializable T>
void save_and_load(const T& obj) {
std::stringstream ss;

// Сериализация
obj.serialize(ss);
std::cout << "Serialized: " << ss.str() << std::endl;

// Десериализация
T loaded = T::deserialize(ss);
std::cout << "Deserialized successfully" << std::endl;
}

// Использование
void example() {
Person p{"Alice", 25};
save_and_load(p); // Работает

// save_and_load(42); // Ошибка компиляции
}



😡 Частые ошибки:

Забывают про static методы в концептах
Не учитывают const-correctness
Создают слишком жёсткие требования


⛄️ Практический совет:

Концепты помогают создавать self-documenting API и ловить ошибки на этапе компиляции.

Библиотека C/C++ разработчика #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
👍84
⚡️ Фича дня: std::views::transform

🐼 Проблема:

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


✏️ Решение:

views::transform создает ленивое представление с трансформацией на лету.

🔴 До:
cppstd::vector<std::string> strings;
for (const auto& num : numbers) {
strings.push_back(std::to_string(num));
}


🟢 После:
auto string_view = numbers | std::views::transform([](int x) { 
return std::to_string(x);
});



❗️Практические применения:

- Преобразование данных в конвейерах
- Форматирование без промежуточных контейнеров
- Цепочки трансформаций

⚡️ Используете transform views для оптимизации?

Библиотека C/C++ разработчика #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
std::chrono — работа со временем

Используете time_t и clock() для измерения времени?


std::chrono в C++11 предоставляет типобезопасную работу со временем. Высокая точность, читаемый код и портабельность.

👉 Подключение:

#include <chrono>
using namespace std::chrono;


💡 Примеры использования:

auto start = high_resolution_clock::now();
expensive_operation();
auto end = high_resolution_clock::now();

auto duration = duration_cast<milliseconds>(end - start);
std::cout << "Operation took: " << duration.count() << "ms" << std::endl;


std::this_thread::sleep_for(seconds(2));         // Спать 2 секунды
std::this_thread::sleep_for(milliseconds(500)); // Спать 500 мс
std::this_thread::sleep_for(2s); // C++14 literals


Основные типы:
— duration для промежутков времени
— time_point для моментов времени
— clock для источников времени

Часы (clocks):
— system_clock системное время
— steady_clock монотонное время
— high_resolution_clock наивысшая точность

Единицы времени:
— nanoseconds, microseconds, milliseconds
— seconds, minutes, hours
— Пользовательские единицы

Библиотека C/C++ разработчика #буст
🔥111
✏️ Промпт дня: Улучшение обработки ошибок

Обработка ошибок — один из самых критичных аспектов разработки на C++. Неправильная обработка исключений может привести к утечкам памяти, неопределенному поведению и краху приложения.


☀️ Решение с помощью AI

Для улучшения системы обработки ошибок в вашем коде используйте следующий промпт:

How can I improve the error handling in my C++ code? [ВАШ КОД]



🧋 Пример трансформации

До:

int divide(int a, int b) {
return a / b; // Деление на ноль = краш
}

std::vector<int> readFile(const std::string& filename) {
std::ifstream file(filename);
std::vector<int> data;
int value;
while (file >> value) {
data.push_back(value);
}
return data; // Что если файл не открылся?
}



После (с улучшенной обработкой ошибок):

#include <stdexcept>
#include <optional>

std::optional<int> divide(int a, int b) {
if (b == 0) {
return std::nullopt;
}
return a / b;
}

std::vector<int> readFile(const std::string& filename) {
std::ifstream file(filename);
if (!file.is_open()) {
throw std::runtime_error("Cannot open file: " + filename);
}

std::vector<int> data;
int value;
while (file >> value) {
data.push_back(value);
}

if (file.bad()) {
throw std::runtime_error("Error reading file: " + filename);
}

return data;
}


✏️ Как часто в вашем коде встречаются необработанные ошибки? Пишите в комментариях.

Библиотека C/C++ разработчика #буст
👍31🤔1
🍪 Как эволюционировала работа с типами в C++: от C++98 до C++23

🌳 Помните времена, когда приходилось писать std::vector<std::vector<int> > с пробелом? Давайте посмотрим, как изменилась работа с типами за 25 лет!


✏️ Пошаговая эволюция:

1️⃣ C++98 - Боль и страдания

//Verbosity nightmare
std::vector<std::pair<std::string, int> > vec; // пробел обязателен!
for (std::vector<std::pair<std::string, int> >::iterator it = vec.begin();
it != vec.end(); ++it) {
// работаем с *it
}


2️⃣ C++11 - Первые облегчения

// auto и range-based for
std::vector<std::pair<std::string, int>> vec; // >> теперь OK!
for (auto& item : vec) {
// намного чище!
}


3️⃣ C++17 - Магия template argument deduction

// Не нужно указывать типы
std::vector vec{std::pair{"hello", 42}, {"world", 24}}; // CTAD!
std::optional opt = some_function(); // тип выводится автоматически

// Structured bindings
for (auto [name, value] : vec) {
std::cout << name << ": " << value << "\n";
}


4️⃣ C++20 - Concepts и constraints

#include <concepts>

template<std::integral T> // Концепты!
auto process(T value) {
return value * 2;
}

// Abbreviated function templates
auto add(std::integral auto a, std::integral auto b) {
return a + b;
}


5️⃣ C++23 - Еще больше удобства

// if consteval для compile-time проверок
constexpr auto get_value() {
if consteval {
return 42; // compile-time версия
} else {
return expensive_runtime_calc(); // runtime версия
}
}

// Multidimensional subscript operator
matrix[1, 2, 3] = value; // вместо matrix[1][2][3]



💔 Частые ошибки:

Злоупотребление auto: auto x = 5u; может быть неочевидным
Явные типы для API: std::uint32_t count = get_count();

Игнорирование concepts: старые template error messages
Используйте standard concepts: std::integral, std::floating_point

Библиотека C/C++ разработчика #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥102
✏️ conjure_enum: легковесное перечисление C++20


🔹 Зачем?

Работа с перечислениями (enum) в C++ часто требует дополнительного кода: преобразование в строку, проверка значений, итерация по всем вариантам. Библиотека conjure_enum автоматизирует эту рутину!


🔹 Что умеет?

Генерация to_string() для enum
Проверка валидности значений (is_valid)
Итерация по всем элементам enum
Поддержка enum и enum class
Минимальный оверхед (всё вычисляется на этапе компиляции)


🔹 Пример использования:

#include "conjure_enum.h"

CONJURE_DEFINE_ENUM(Color, Red, Green, Blue)

int main() {
Color c = Color::Green;
std::cout << conjure_enum::to_string(c); // "Green"
std::cout << conjure_enum::is_valid(42); // false
for (Color value : conjure_enum::values<Color>()) { ... }
}



🔹 Плюсы:

✔️ Заголовочный-only (просто подключи conjure_enum.h)
✔️ Не требует C++20 (работает даже на C++11)
✔️ Лёгкая интеграция в существующий код


💡 Кому пригодится?

— Тем, кто устал писать switch-case для enum-ов
— Если нужна удобная отладка (вывод значений в лог)
— Для валидации конфигов/сетевых данных

🔗 Ссылка

Библиотека C/C++ разработчика #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥91
🏠 How to: Как правильно реализовать оператор присваивания

Перегрузка operator= - одна из самых коварных тем в C++. Часто приводит к багам.


🍴Правила безопасного operator=:

1️⃣ Проверяем самоприсваивание
2️⃣ Создаём временную копию
3️⃣ Используем swap idiom


class MyString {
private:
char* data;
size_t length;

public:
// Правильный operator=
MyString& operator=(const MyString& other) {
if (this == &other) return *this; // самоприсваивание

// Создаём временную копию
char* temp = new char[other.length + 1];
strcpy(temp, other.data);

// Освобождаем старые данные
delete[] data;

// Присваиваем новые
data = temp;
length = other.length;

return *this;
}

// Лучше через copy-and-swap
MyString& operator=(MyString other) { // копия по значению
swap(*this, other);
return *this;
}
};


Опасность:

Без проверки самоприсваивания можем удалить данные, которые копируем.

Золотое правило:

Copy-and-swap никогда не подведёт.

Библиотека C/C++ разработчика #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
4🥰1
Чек-лист: Оптимизация времени компиляции

Долгая компиляция убивает продуктивность. Ускорьте сборку вашего C++ проекта.


🎯 Структура проекта

✓ Используйте forward declarations вместо #include где возможно
✓ Минимизируйте зависимости в header файлах
✓ Применяйте Pimpl idiom для скрытия деталей имплементации
✓ Разбивайте большие файлы на модули


🎯 Современные возможности

✓ Переходите на C++20 modules постепенно
✓ Используйте precompiled headers для стабильных зависимостей
✓ Настройте distributed compilation (distcc, Incredibuild)


🎯 Инструменты и настройки

✓ Включите параллельную компиляцию (-j флаг)
✓ Используйте ccache для кеширования результатов
✓ Профилируйте время компиляции с -ftime-trace (Clang)
✓ Настройте incremental linking


Как измерить результат: Замеряйте время полной и инкрементальной сборки регулярно.

Библиотека C/C++ разработчика #буст
6🔥5
👾 Ржавеющие плюсы: как внедрять современные проверки С++

💡Разработчик из Яндекс.Такси поделился опытом масштабного внедрения инструментов безопасности C++ — от статических анализаторов до санитайзеров.

❗️ Ключевые моменты доклада:

• внедрение CPP Hardening, Clang Lifetime Annotation и санитайзеров заняло 4 месяца
• из 40 тысяч падений тестов 20 тысяч были вызваны одной ошибкой
• санитайзеры нашли несколько сотен реальных багов в промышленной кодовой базе

Основной фокус — пятиэтапный процесс внедрения: тестирование проверок, анализ ошибок, постепенная починка багов, координация между командами и определение момента завершения работ.

Особенно актуально для компаний с большими legacy кодовыми базами, где безопасность кода критична для стабильности сервисов.

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

👉 Видео

Библиотека C/C++ разработчика #буст
4👾1
📰 Свеженькое из мира C++

Подготовили подборку самых интересных материалов за неделю о разных аспектах программирования и интересных проектах в мире C++.

😎 Полезное:

Как правильно реализовать оператор присваивания — реализация своего оператора присваивания
Оптимизация времени компиляции — чек-лист по улучшению времени компиляции кода
Как внедрять современные проверки С++ — видео о подходах к внедрению инструментов безопасности

🖨Интересные проекты:

NanaZip — архиватор файлов с открытым исходным кодом (написан на основе исходного кода исходного кода 7-Zip)
RocksDB — постоянное хранилище ключей и значений для флэш-памяти и оперативной памяти
Atmosphère — кастомизированная прошивка для Nintendo Switch

Библиотека C/C++ разработчика #буст
👍21
🍙 How-to: Как избежать memory ordering проблем в многопоточном коде


💭 Race conditions в атомарных операциях - одна из самых коварных проблем. Разбираемся с memory ordering.


✏️ Пошаговое решение:

Проблема: Неопределенное поведение при concurrent доступе

//  ОПАСНО: data race!
std::atomic<bool> ready{false};
int data = 0;

// Thread 1
data = 42;
ready.store(true); // неопределенный ordering!

// Thread 2
if (ready.load()) {
process(data); // может быть 0 или 42!
}



Решение: Explicit memory ordering

//  ПРАВИЛЬНО: используем memory_order
std::atomic<bool> ready{false};
int data = 0;

// Thread 1
data = 42;
ready.store(true, std::memory_order_release); // освобождаем

// Thread 2
if (ready.load(std::memory_order_acquire)) { // захватываем
process(data); // гарантированно 42!
}


⚠️ Частые ошибки:

• Использование memory_order_relaxed везде
• Забывание про acquire-release семантику
• Смешивание атомарных и неатомарных операций

Библиотека C/C++ разработчика #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔5👍2
👾 Clang получает режим усиленной безопасности

Разработчики Clang обсуждают добавление флага -fhardened по аналогии с GCC 14.

🏖️ Новый режим одной командой активирует целый набор защитных механизмов:

• Инициализация переменных нулями
• Защита стека и от переполнений
• Рандомизация адресов
• Усиленные проверки библиотек
• Дополнительные предупреждения

Проблема: разрозненность опций безопасности в C/C++. Многие разработчики просто не знают о их существовании или забывают включать.

Решение: единый флаг, который «из коробки» делает код безопаснее.
Конечно, это костыли для языков 70-80х годов, но лучше поздно чем никогда.

👉 Заметка

Библиотека C/C++ разработчика #буст
💡 Фича дня: std::exchange (C++14)

Часто при написании операторов присваивания или swap-функций приходится сохранять старое значение, заменяя его новым. Код получается многословным и подверженным ошибкам.

std::exchange атомарно заменяет значение переменной и возвращает старое значение — всё в одной строке.


До:

T old_value = obj;
obj = new_value;
return old_value;


После:

return std::exchange(obj, new_value);


Код становится более читаемым, безопасным и выразительным. Особенно полезно в RAII-классах и при работе с умными указателями.

Библиотека C/C++ разработчика #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
👍151
🌐 Чек-лист: как искать работу

Чтобы не застрять в вечной отладке своей карьеры, держим в голове (и перед глазами) понятный план. Вот чек-лист на период поиска:

Обновите резюме и профиль (да, и GitHub тоже)

Ваш профиль — это витрина. Убедитесь, что в нём отражены:
• актуальные технологии (например, .NET 6/7/8, Blazor, ASP.NET, Azure и т. д.).
• понятные результаты («реализовал систему логирования» , а не «писал код»).
• ссылки на GitHub с чистыми, осмысленными проектами — лишнее желательно скрыть или удалить.

Сформулируйте ключевые навыки и корректные поисковые запросы.

Большинство рекрутеров используют автоматические фильтры. Включите в резюме чёткие названия технологий: Entity Framework Core, LINQ, RabbitMQ, Docker, CI/CD, Kubernetes.

Следите за вакансиями регулярно, но без стресса

• Настройте уведомления на LinkedIn, Habr Career, hh.
• Подпишитесь на каналы с вакансиями, например, наш канал с вакансиями для шарпистов.

Готовьтесь к собеседованиям заранее

• Освежите базовые концепции вроде async/await, Dependency Injection, SOLID, разберитесь в нюансах работы ASP.NET.
• Подумайте заранее, какие проекты вы можете описать как удачные кейсы.
• Поработайте над формулировками, которые показывают ваш вклад — рекрутеры ценят конкретику.

Сколько ищете работу? Пару дней или пару месяцев? Пишите в комментарии👇

Proglib Academy #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
🧨 Range views: детали реализации, неочевидное поведение и влияние на производительность

Современные диапазоны могут заменить 90% ваших циклов — но есть подводные камни.

Разработчик из Яндекса разобрал детали реализации ranges, которые изменят ваш подход к обработке данных:

Композируемость алгоритмов — строите цепочки операций через pipe operator вместо вложенных циклов
Ленивые вычисления — всё выполняется за один проход, экономя память и время
Скрытое кэширование — почему константные объекты могут не компилироваться и как это обойти
Проблемы с join и split — когда повторная итерация приводит к неопределённому поведению
Оптимизация производительности — тесты показывают эквивалентность с ручным кодом
Практические ловушкиdouble calls, broken constness и другие неочевидные эффекты

📹 Видео

Библиотека C/C++ разработчика #буст
3
📰 Свеженькое из мира C++

Подготовили подборку самых интересных материалов за неделю о разных аспектах программирования и интересных проектах в мире C++.

😼 Интересное:

Clang получает режим усиленной безопасности — добавление в Clang нового флага безопасности
Range views — детали реализации, неочевидное поведение и влияние на производительность
Сколько ты стоишь как разработчик — статья о том как оценить свою стоимость на рынке

😎 Полезное:

Как избежать memory ordering проблем в многопоточном коде — полезные советы по улучшению многопоточного кода
std::exchange — современный способ обмена значениями

🖨️Интересные проекты:

Solidity — язык высокого уровня для реализации смарт-контрактов
Flameshot — мощное, но простое в использовании программное обеспечение для создания снимков экрана
Eclipse SUMO — пакет для моделирования дорожного движения с открытым исходным кодом

Библиотека C/C++ разработчика #буст
🥳 How to: RAII + Custom Deleters для ресурсов

Если нужно управлять сложными ресурсами, то можно воспользоваться костюмными deleters.

‼️ Проблема:

FILE*, сокеты, OpenGL объекты требуют специального освобождения

✏️ Решение:


// Универсальный RAII wrapper

template<typename T, typename Deleter>
class Resource {
T resource;
Deleter deleter;
bool owns_resource = true;
public:
Resource(T resource, Deleter deleter) : resource(resource)
, deleter(deleter) {}

~Resource() { if(owns_resource) deleter(resource); }

Resource(Resource&& other) : resource(other.resource)
, deleter(std::move(other.deleter))
, owns_resource(other.owns_resource)
{ other.owns_resource = false; }

Resource(const Resource&) = delete;
T get() const { return resource; }
T release() { owns_resource = false; return resource; }
};


// Использование
auto file = Resource(fopen("data.txt", "r"),
[](FILE* f) { if(f) fclose(f); });


🍪 Совет:

Для совместимости с STL удобно использовать std::unique_ptr с кастомным deleter.


Библиотека C/C++ разработчика

#буст
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13🥰3