Типобезопасные перечисления — enum class вместо старого enum!
Обычный
Сначала посмотрим на «старый»
Теперь перепишем на
🔥 Переход на
📣 C++ Ready | #практика
Обычный
enum неявно приводится к int и даёт сравнивать разные перечисления друг с другом — легко наделать странных багов.Сначала посмотрим на «старый»
enum и его проблемы:enum Color { Red, Green, Blue };
enum Status { Ok, Error };
int main() {
Color c = Red;
if (c == Ok) { } // компилируется, хотя Color и Status — разные enum'ы
}Теперь перепишем на
enum class, чтобы каждое перечисление стало отдельным типом с собственной областью имён:enum class Color { Red, Green, Blue };
enum class Status { Ok, Error };
int main() {
Color c = Color::Red;
Status s = Status::Ok;
// if (c == s) { } // ошибка компиляции: разные типы
}enum class не приводится к int по умолчанию, не пересекается по именам и сразу показывает, к какому именно набору значений относится переменная.enum class — простой шаг к более безопасному и читаемому коду с перечислениями.Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤9🔥4😁1
❤12👍6🔥5
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥24👍7❤5🤝2
Как запретить опасное копирование ещё на этапе компиляции?
Класс часто владеет ресурсом: файл, сокет, мьютекс.
Если такой объект случайно скопировать, ресурс могут закрыть дважды или использовать после освобождения — ловим странные баги.
В современном C++ не нужно придумывать трюки с приватными конструкторами.
Достаточно явно запретить операции через
Теперь любой код, который останавливается ещё на стадии сборки, например:
Тем же приёмом можно отключать нежелательные перегрузки функций:
🔥 Итог:
«эту операцию делать нельзя», и превратить потенциальный рантайм-баг в понятную ошибку компиляции.
📣 C++ Ready | #совет
Класс часто владеет ресурсом: файл, сокет, мьютекс.
Если такой объект случайно скопировать, ресурс могут закрыть дважды или использовать после освобождения — ловим странные баги.
В современном C++ не нужно придумывать трюки с приватными конструкторами.
Достаточно явно запретить операции через
= delete:struct File {
File(const std::string& path);
File(const File&) = delete;
File& operator=(const File&) = delete;
};Теперь любой код, который останавливается ещё на стадии сборки, например:
File a{"data.txt"};
File b = a; // ❌ не скомпилируетсяТем же приёмом можно отключать нежелательные перегрузки функций:
void print(double);
void print(int) = delete; // запретить неявное приведение int → double
= delete — простой способ сказать компилятору«эту операцию делать нельзя», и превратить потенциальный рантайм-баг в понятную ошибку компиляции.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤16🔥9🤝6👍1
Запускаем несколько рабочих потоков заранее, кладём задачи в общую очередь — потоки по сигналу забирают и выполняют их, без создания новых
std::thread на каждую задачу.В этой задаче:
• Почувствуешь разницу между хаотичным запуском задач и порядком;
• Увидишь, как несколько потоков спокойно делят очередь;
• Замечаешь, как код берёт рутину выбора на себя.
Покажет использование в
main и почему порядок вывода «плавает». Добавление std::future сделает пул ещё удобнее.Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20👍10❤7🤝1
Безопасный union — std::variant и std::visit!
Обычный
Сначала объявим удобный псевдоним для значения, которое может быть
Теперь напишем функцию-обработчик, которая по-разному реагирует на каждый возможный тип внутри
И маленький пример использования: одно и то же значение по очереди становится разными типами, а
🔥
📣 C++ Ready | #практика
Обычный
union в C++ легко приводит к UB: нужно самому следить, какой тип там сейчас хранится. std::variant из стандарта делает то же самое, но безопасно: внутри хранится ровно один из перечисленных типов и следит за активным вариантом.Сначала объявим удобный псевдоним для значения, которое может быть
int, double или std::string:using Value = std::variant<int, double, std::string>;
Теперь напишем функцию-обработчик, которая по-разному реагирует на каждый возможный тип внутри
Value с помощью std::visit:void handle(const Value& v) {
std::visit([](const auto& x) {
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, int>) {
std::cout << "int: " << x << "\n";
} else if constexpr (std::is_same_v<T, double>) {
std::cout << "double: " << x << "\n";
} else {
std::cout << "string: " << x << "\n";
}
}, v);
}И маленький пример использования: одно и то же значение по очереди становится разными типами, а
std::visit всегда вызывается с актуальным вариантом:int main() {
Value v = 42;
handle(v); // int: 42
v = 3.14;
handle(v); // double: 3.14
v = std::string("hello");
handle(v); // string: hello
return 0;
}std::variant + std::visit дают безопасный, типобезопасный union и аккуратную обработку нескольких типов без кастов и ручного трекинга «какой тип лежит внутри».Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍9❤6👎4🤝1
Когда вывод разбросан по
cout и printf, его трудно менять; удобнее собрать текст по шаблону и лишь подставлять нужные значения.В этом гайде:
• Посмотрим, как собирать аккуратный текст из значений;
• Разберём примеры выравнивания и красивых табличных чисел;
• Сделаем простой и понятный лог без склейки строк.
Освоив такой подход, вы сможете держать формат текста в одном месте и менять его без боязни сломать вывод.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15❤13🤝9👍2