Библиотека 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
加入频道
🍪 Doxygen

❗️Проблема:

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


Решение:

Doxygen автоматически генерирует документацию из специальных комментариев в коде. Инструмент создает HTML, PDF и другие форматы документации с диаграммами классов и зависимостей.


✏️ Пример кода:

/**
* @brief Класс для работы с геометрическими фигурами
* @author Имя разработчика
* @date 2024-01-15
*/
class Shape {
protected:
double width; ///< Ширина фигуры
double height; ///< Высота фигуры

public:
/**
* @brief Конструктор с параметрами
* @param w Ширина фигуры (должна быть > 0)
* @param h Высота фигуры (должна быть > 0)
* @throw std::invalid_argument при некорректных параметрах
*/
Shape(double w, double h) : width(w), height(h) {
if (w <= 0 || h <= 0) {
throw std::invalid_argument("Размеры должны быть положительными");
}
}

/**
* @brief Вычисляет площадь фигуры
* @return Площадь в квадратных единицах
* @note Виртуальный метод, должен быть переопределен
*/
virtual double calculateArea() const = 0;

/// Деструктор по умолчанию
virtual ~Shape() = default;
};


# Генерация документации
doxygen -g # Создание конфигурационного файла
doxygen Doxyfile # Генерация документации



Преимущества:

— Автоматическая генерация документации из кода
— Поддержка множества выходных форматов
— Создание диаграмм классов и зависимостей
— Синхронизация документации с кодом


🐥 А как вы пишите документацию? Пишите в комментариях.


🐸Библиотека C/C++ разработчика #буст
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍42🥰1
🚀 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
🔥84
✏️ Промпт дня: Создание юнит-тестов для надёжного кода

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