Когда вызовется ~Socket()?
Anonymous Quiz
40%
Сразу после выброса исключения
20%
После catch-блока
20%
Никогда
20%
Зависит от оптимизаций компилятора
Что делает объект ScopeExit guard([]{ unlock(); }) ?
Anonymous Quiz
0%
Вызывает unlock() сразу при создании
100%
Вызывает unlock() при выходе из области видимости
0%
Вызывает unlock() при перемещении
0%
Не вызывает ничего
🧩 SOLID-принципы C++
Что такое SOLID и для чего он необходим?
1️⃣ S — Single Responsibility
Пояснение: Класс делает узконаправленную задачу
Пример: Logger не должен писать в базу.
2️⃣ O — Open/Closed
Пояснение: Код открыт для расширения, но закрыт для модификации.
Пример: Использование виртуальных функций, шаблонов, полиморфизма.
3️⃣ L — Liskov Substitution
Пояснение: Объекты подклассов можно использовать вместо базовых.
Пример: Если Derived ломает контракт Base, нарушен LSP.
4️⃣ I — Interface Segregation
Пояснение: Лучше несколько маленьких интерфейсов, чем один общий.
5️⃣ D — Dependency Inversion
Пояснение: Зависимости — от абстракций, а не от конкретных реализаций.
Пример: Использование родительского класса для создания экземпляра —
⚙️ Пример использования SOLID
— SRP:
— OCP: можно добавить
— LSP: любой
— ISP: интерфейс компактный.
— DIP: зависимости через абстракции.
Подводя итог, SOLID — набор основных принципов, позволяющих писать читаемый, тестируемый и расширяемый C++ код.
#cpp_tips
Что такое SOLID и для чего он необходим?
1️⃣ S — Single Responsibility
Пояснение: Класс делает узконаправленную задачу
Пример: Logger не должен писать в базу.
2️⃣ O — Open/Closed
Пояснение: Код открыт для расширения, но закрыт для модификации.
Пример: Использование виртуальных функций, шаблонов, полиморфизма.
3️⃣ L — Liskov Substitution
Пояснение: Объекты подклассов можно использовать вместо базовых.
Пример: Если Derived ломает контракт Base, нарушен LSP.
4️⃣ I — Interface Segregation
Пояснение: Лучше несколько маленьких интерфейсов, чем один общий.
5️⃣ D — Dependency Inversion
Пояснение: Зависимости — от абстракций, а не от конкретных реализаций.
Пример: Использование родительского класса для создания экземпляра —
unique_ptr<IService> вместо unique_ptr<MyService>.⚙️ Пример использования SOLID
struct IShape {
virtual double area() const = 0;
virtual ~IShape() = default;
};
class Circle : public IShape {
double r_;
public:
explicit Circle(double r) :
r_(r) {}
double area() const override
{
return 3.14 * r_ * r_;
}
};— SRP:
Circle отвечает только за площадь круга.— OCP: можно добавить
Rectangle, не меняя IShape.— LSP: любой
IShape заменим на Circle.— ISP: интерфейс компактный.
— DIP: зависимости через абстракции.
Подводя итог, SOLID — набор основных принципов, позволяющих писать читаемый, тестируемый и расширяемый C++ код.
#cpp_tips
🧬 CRTP (Curiously Recurring Template Pattern)
CRTP — это шаблон, где класс-наследник передаёт себя в качестве параметра шаблона базовому классу.
А наследник выглядит так:
⚙️ Как это работает
Когда ты вызываешь:
Базовый класс вызывает метод
при этом без виртуальных функций — всё статически известно на этапе компиляции.
🚀 Где это полезно:
— Mixin — добавление поведения к классам без виртуальности.
— Policy-based design — подмена стратегий через шаблонные параметры.
— Статический полиморфизм — альтернатива
— Ограничение интерфейса наследников — например, через
🧠 Пример Mixin с CRTP
— Без virtual
— Без динамической памяти
— Гибко и эффективно
В итоге имеем:
CRTP — способ реализовать полиморфизм, заменив виртуальные вызовы статическим связыванием на этапе компиляции.
#cpp_tips
Как использовать шаблоны, а не виртуальность, чтобы дать базовому классу знать о потомке?
CRTP — это шаблон, где класс-наследник передаёт себя в качестве параметра шаблона базовому классу.
template <typename Derived>
class Base
{
public:
void interface()
{
static_cast<Derived*>
(this)->implementation();
}
};
А наследник выглядит так:
class Derived : public Base<Derived>
{
public:
void implementation()
{
std::cout << "Derived func\n";
}
};
⚙️ Как это работает
Когда ты вызываешь:
Derived d;
d.interface();
Базовый класс вызывает метод
implementation() у конкретного типа Derived,при этом без виртуальных функций — всё статически известно на этапе компиляции.
🚀 Где это полезно:
— Mixin — добавление поведения к классам без виртуальности.
— Policy-based design — подмена стратегий через шаблонные параметры.
— Статический полиморфизм — альтернатива
virtual, но без runtime overhead.— Ограничение интерфейса наследников — например, через
enable_if и SFINAE.🧠 Пример Mixin с CRTP
template <typename Derived>
class Printable
{
public:
void print() const
{
std::cout <<
static_cast<const Derived*>
(this)->toString();
}
};
class Point : public Printable<Point>
{
public:
Point(int x, int y) : x_(x), y_(y) {}
std::string toString() const
{
return std::to_string(x_) + ","
+ std::to_string(y_);
}
private:
int x_, y_;
};
Point p(2, 3);
p.print(); // 2,3
— Без virtual
— Без динамической памяти
— Гибко и эффективно
В итоге имеем:
CRTP — способ реализовать полиморфизм, заменив виртуальные вызовы статическим связыванием на этапе компиляции.
#cpp_tips
Что выведет программа
Anonymous Quiz
50%
General
50%
Int second
0%
Ошибка компиляции
0%
Неопределенное поведение
⚙️ Type Traits: когда типы становятся логикой
Примеры Type Traits
🧠 Type Traits — шаблонные конструкции, которые предоставляют информацию о свойствах типов во время компиляции
Используются в
Примеры Type Traits
template<typename T>
struct is_pointer
{
static constexpr bool value = false;
};
template<typename T>
struct is_pointer<T*>
{
static constexpr bool value = true;
};
assert(is_pointer<int*>::value);
🧠 Type Traits — шаблонные конструкции, которые предоставляют информацию о свойствах типов во время компиляции
Используются в
std::enable_if, concepts, std::move.Какой trait определяет, является ли тип числовым?
Anonymous Poll
0%
std::is_arithmetic
0%
std::is_integral
100%
std::is_numeric
🎯 Policy-based Design: шаблонная настройка поведения
Пример реализации:
✅ Вместо наследования от суперкласса составляем объект из политик, что позволяет легко менять поведение без лишнего кода.
Пример реализации:
template<typename ThreadPolicy, typename LogPolicy>
class Engine : private ThreadPolicy, private LogPolicy
{
public:
void run()
{
this->log("Starting...");
this->lock();
this->unlock();
}
};
✅ Вместо наследования от суперкласса составляем объект из политик, что позволяет легко менять поведение без лишнего кода.
Что проще изменить в Policy-based подходе?
Anonymous Poll
0%
Интерфейс базового класса
0%
Структуру иерархии
100%
Поведение
Expression Templates
Или магия ленивых выражений
Шаблоны выражений - это метод метапрограммирования шаблонов C++, который создает структуры, представляющие вычисления во время компиляции, где выражения вычисляются только по мере необходимости для создания эффективного кода для всего вычисления.
Таким образом, шаблоны выражений позволяют программистам обойти обычный порядок вычисления на языке C++ и добиться оптимизации, такой как объединение циклов.
Пример:
🧠 Такие паттерны лежат в основе библиотек Eigen, Blitz++, Armadillo. Они предотвращают создание временных объектов — всё оптимизируется на этапе компиляции.
Или магия ленивых выражений
Шаблоны выражений - это метод метапрограммирования шаблонов C++, который создает структуры, представляющие вычисления во время компиляции, где выражения вычисляются только по мере необходимости для создания эффективного кода для всего вычисления.
Таким образом, шаблоны выражений позволяют программистам обойти обычный порядок вычисления на языке C++ и добиться оптимизации, такой как объединение циклов.
Пример:
template<typename L, typename R>
struct Add
{
L const& l; R const& r;
auto eval() const
{
return l.eval() + r.eval();
}
};
struct Value
{
double v;
auto eval() const
{
return v;
}
};
🧠 Такие паттерны лежат в основе библиотек Eigen, Blitz++, Armadillo. Они предотвращают создание временных объектов — всё оптимизируется на этапе компиляции.
Static Interface (Concepts)
Static Interface: контракты времени компиляции
🧠 Concepts — это compile-time контракты.
Компилятор гарантирует, что тип соответствует интерфейсу.
Это безопасный и быстрый способ добавления ограничений к создаваемым объектам
Static Interface: контракты времени компиляции
template<typename T>
concept Drawable = requires(T obj)
{
obj.draw();
};
template<Drawable T>
void render(T obj)
{
obj.draw();
}
🧠 Concepts — это compile-time контракты.
Компилятор гарантирует, что тип соответствует интерфейсу.
Это безопасный и быстрый способ добавления ограничений к создаваемым объектам
Две ассоциативные структуры, два разных назначения.
map
— Красно-чёрное дерево
— Операции за
O(log n)— Сохраняет сортировку ключей
unordered_map
— Хеш-таблица
— Амортизированная
O(1)— Нет сортировки
Но, может переполняться и ребалансироваться
std::unordered_map<std::string, int> id;
id["Alice"] = 5;
💡 Если нужны сортированные ключи — map. Если нужна скорость — unordered_map.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Что делает map.lower_bound(k)?
Anonymous Poll
25%
Возвращает все итераторы на элементы ≤ k
0%
Возвращает итератор на элемент с ключом ≤ k
75%
Возвращает итератор на первый элемент ≥ k