С++ для интервью
37 subscribers
10 photos
Готовься к собеседованиям по C++ эффективно: реальные вопросы, типичные HR уловки, примеры кода и объяснения.
Каждый пост — один шаг ближе к офферу 💼
Download Telegram
📦 Рассмотрим важный концепт языка C++. Move semantics.

💭Основная идея:
Копировать дорого. Перемещать — почти бесплатно


Современный 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
💡 Правильный ответ: 2 и 3

🤓 Пояснения: Если fopen вернул nullptr, fclose(nullptr) — UB.
Кроме того, копирование File приведёт к двойному закрытию — класс должен быть не копируемым, а перемещаемым.
Please open Telegram to view this post
VIEW IN TELEGRAM
Что произойдёт при исключении в конструкторе?
Что делает такой шаблон RAII-защитника?
🧩 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

Пояснение: Зависимости — от абстракций, а не от конкретных реализаций.
Пример: Использование родительского класса для создания экземпляра — 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 — это шаблон, где класс-наследник передаёт себя в качестве параметра шаблона базовому классу.

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
🧩 Тест 1 — Как работает вывод типов шаблона
Что выведет программа
Anonymous Quiz
0%
int
0%
double
100%
Ошибка компиляции
0%
auto
⚙️ Тест 2 — Передача по ссылке и вывод типов
Какой тип будет у T
Anonymous Quiz
0%
int
100%
const int
0%
int &
0%
const int &
🧩 Тест 3 — Как работает частичная специализация
⚙️ 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