⚡️ Задача 3 — "Кто владелец строки?"
std::string getName() {
return "Bjarne";
}
auto&& name = getName();
std::cout << name << "\n";⚙️ Что выведет программа?
Anonymous Quiz
21%
Неопределённый вывод
50%
Выведет Bjarne
14%
Висячая ссылка
14%
Ошибка компиляции
⚠️ Самый последний способ не будет компилироваться, так как перестановка полей для инициализации класса не допустима.
struct Entity
{
int x = 0, y = 0;
};
int main()
{
Entity entity_1;
Entity entity_2(2);
Entity entity_3(3, 3);
Entity entity_4 { .x = 4 };
Entity entity_5 { .x = 5, .y = 5 };
Entity entity_6 { .y = 6 };
// Entity entity_7 { .y = 7, .x = 7 }; // error
}
#cpp_tips
Please open Telegram to view this post
VIEW IN TELEGRAM
📦 Рассмотрим важный концепт языка C++. Move semantics.
💭Основная идея:
Современный C++ , начиная с C++11, позволяет не копировать объекты,
а просто передавать владение ресурсом. Это и есть move semantics.
📋 Копирование → создаёт новую строку, копирует все символы.
🚚 Перемещение → "забирает" указатель у a, а a становится пустой.
⚠️ std::move — это не move, это cast
🧠 std::move не перемещает ничего сам по себе!
Он лишь превращает объект в rvalue-ссылку,
давая компилятору понять:
❗️Важное правило: после std::move — не трогай объект
❓ Когда использовать std::move
✅ Возврат временного объекта из функции:
✅ При передаче в контейнер:
🚫 Не используем при передаче по const& — const запрещает move!
🎯 Что мы имеет в итоге:
1️⃣ std::move — это rvalue cast, не “перемещение”.
2️⃣ Move-конструктор переносит ресурсы, оставляя источник “пустым”.
3️⃣ После move объект можно уничтожать, но не использовать.
4️⃣ const запрещает move.
Пользуйтесь, друзья, и делитесь со своими товарищами программистами🤝
#cpp_tips #cpp_question
💭Основная идея:
Копировать дорого. Перемещать — почти бесплатно
Современный C++ , начиная с C++11, позволяет не копировать объекты,
а просто передавать владение ресурсом. Это и есть move semantics.
std::string a = "Hello";
std::string b = a; // копирование
std::string c = std::move(a); // перемещение
📋 Копирование → создаёт новую строку, копирует все символы.
🚚 Перемещение → "забирает" указатель у a, а a становится пустой.
⚠️ std::move — это не move, это cast
🧠 std::move не перемещает ничего сам по себе!
Он лишь превращает объект в rvalue-ссылку,
давая компилятору понять:
Я больше не буду использовать этот объект — можешь забирать ресурсы.
❗️Важное правило: после std::move — не трогай объект
std::string s = "Hello";
auto t = std::move(s);
std::cout << s; // ❌
❓ Когда использовать std::move
✅ Возврат временного объекта из функции:
std::string make() {
std::string s = "Data";
return s; // RVO или move
}✅ При передаче в контейнер:
vec.push_back(std::move(obj));
🚫 Не используем при передаче по const& — const запрещает move!
void f(const std::string& s) {
auto t = std::move(s); // ❌ всё равно копия
}🎯 Что мы имеет в итоге:
1️⃣ std::move — это rvalue cast, не “перемещение”.
2️⃣ Move-конструктор переносит ресурсы, оставляя источник “пустым”.
3️⃣ После move объект можно уничтожать, но не использовать.
4️⃣ const запрещает move.
Пользуйтесь, друзья, и делитесь со своими товарищами программистами
#cpp_tips #cpp_question
Please open Telegram to view this post
VIEW IN TELEGRAM
Где здесь ошибка в RAII-классе?
Anonymous Poll
0%
Всё корректно
100%
Нужно объявить delete для конструктора копирования
100%
Нужно проверить f перед fclose
0%
Нельзя копировать объект
Кроме того, копирование File приведёт к двойному закрытию — класс должен быть не копируемым, а перемещаемым.
Please open Telegram to view this post
VIEW IN TELEGRAM
В чём суть идиомы RAII?
Anonymous Quiz
50%
Обеспечивает освобождение ресурсов в деструкторе
25%
Автоматически оптимизирует память
25%
Гарантирует потокобезопасность
0%
Ускоряет выполнение кода
Почему RAII-объект часто имеет move, но не copy?
Anonymous Quiz
0%
Чтобы избежать утечек при исключениях
33%
Чтобы можно было передавать владение ресурсом
33%
Чтобы избежать дорогостоящего копирования
33%
Просто потому что это современный стиль
Когда вызовется ~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