🧠 Вопрос из реального интервью для понимания отличий языка C++ от C (junior):
👉 Чем отличается
Ответ тезисно:
2️⃣
3️⃣
4️⃣
5️⃣
#cpp_question #cpp_tips
👉 Чем отличается
new от malloc?Ответ тезисно:
1️⃣ new/delete используется в C++, а malloc/free — в C2️⃣
new вызывает конструктор, malloc — нет. 3️⃣
new возвращает указатель конкретного типа, malloc — void*. 4️⃣
new выбрасывает исключение std::bad_alloc, malloc — возвращает nullptr. 5️⃣
delete вызывает деструктор, free — просто освобождает память.#cpp_question #cpp_tips
🧠 Частый вопрос на знание ключевых слов языка
Что делает ключевое слово explicit? (junior)
📘 Ответ: explicit запрещает неявные преобразования.
Используй его, чтобы избежать случайного вызова конструктора при присваивании.
#cpp_question #cpp_tips
Что делает ключевое слово explicit? (junior)
struct Client {
explicit Client(int x) {}
};
Client a = 5; // ❌ ошибка
Client b(5); // ✅ ок📘 Ответ: explicit запрещает неявные преобразования.
Используй его, чтобы избежать случайного вызова конструктора при присваивании.
#cpp_question #cpp_tips
💬 auto — зло или добро?
💡 Тема: Осознанное использование auto
🎯 Цель: показать, как auto влияет на читаемость, безопасность и оптимизацию
Когда-то auto использовали для вывода типа переменной, теперь же — почти повсюду.
Но стоит ли всегда полагаться на него?
⚙️ Пример 1 — где auto реально помогает
Здесь auto делает код чище и читабельнее.
Без него пришлось бы писать много нечитабельного кода:
⚠️ Пример 2 — где auto вредит
На первый взгляд всё нормально, но sum — это double, а не int.
Если заменить 0.0 на 0, тип поменяется — и можно незаметно получить другую арифметику.
❗️ Иногда auto скрывает ошибки типов, особенно с const, &, && и decltype.
✅ Используй auto, когда:
1) Тип очевиден из правой части;
2) Хочешь избежать дублирования и повысить читаемость.
❌ Не используй auto, когда:
1) Важно сохранить const / &;
2) Выражение возвращает временный объект с неочевидным типом;
3) Тип влияет на поведение.
#cpp_tips
💡 Тема: Осознанное использование auto
🎯 Цель: показать, как auto влияет на читаемость, безопасность и оптимизацию
Когда-то auto использовали для вывода типа переменной, теперь же — почти повсюду.
Но стоит ли всегда полагаться на него?
⚙️ Пример 1 — где auto реально помогает
std::unordered_map<std::string, std::vector<int>> data;
// ...
for (auto& [key, values] : data) {
std::cout << key << " → " << values.size() << "\n";
}
Здесь auto делает код чище и читабельнее.
Без него пришлось бы писать много нечитабельного кода:
for (std::pair<const std::string, std::vector<int>>& entry : data)
⚠️ Пример 2 — где auto вредит
std::vector<int> v = {1, 2, 3};
auto sum = std::accumulate(v.begin(), v.end(), 0.0);На первый взгляд всё нормально, но sum — это double, а не int.
Если заменить 0.0 на 0, тип поменяется — и можно незаметно получить другую арифметику.
❗️ Иногда auto скрывает ошибки типов, особенно с const, &, && и decltype.
✅ Используй auto, когда:
1) Тип очевиден из правой части;
2) Хочешь избежать дублирования и повысить читаемость.
❌ Не используй auto, когда:
1) Важно сохранить const / &;
2) Выражение возвращает временный объект с неочевидным типом;
3) Тип влияет на поведение.
#cpp_tips
⚠️ Самый последний способ не будет компилироваться, так как перестановка полей для инициализации класса не допустима.
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
🧩 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