uz
Feedback

Firibgarlarga uchmang! Telemetrio bunday kanallarni topadi va belgilaydi 👉 Belgini ko‘rmoqchi bo‘lsangiz, obuna bo‘ling

C/C++ | Вопросы собесов

C/C++ | Вопросы собесов

Kanalga Telegram’da o‘tish

Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @sendme_ads

Ko'proq ko'rsatish
4 193
Obunachilar
-224 soatlar
-47 kun
-230 kun
Obunachilarni jalb qilish
Okt '26
Oktabr '26
+49
0 kanalda
Sentabr '26
+64
0 kanalda
Get PRO
Avgust '26
+40
0 kanalda
Get PRO
Iyul '26
+54
0 kanalda
Get PRO
Iyun '26
+46
1 kanalda
Get PRO
May '26
+54
0 kanalda
Get PRO
Aprel '26
+43
0 kanalda
Get PRO
Mart '26
+58
0 kanalda
Get PRO
Fevral '26
+69
0 kanalda
Get PRO
Yanvar '26
+84
0 kanalda
Get PRO
Dekabr '25
+42
0 kanalda
Get PRO
Noyabr '25
+100
0 kanalda
Get PRO
Oktabr '25
+54
0 kanalda
Get PRO
Sentabr '25
+47
0 kanalda
Get PRO
Avgust '25
+77
0 kanalda
Get PRO
Iyul '25
+72
0 kanalda
Get PRO
Iyun '25
+83
0 kanalda
Get PRO
May '25
+83
0 kanalda
Get PRO
Aprel '25
+99
3 kanalda
Get PRO
Mart '25
+88
2 kanalda
Get PRO
Fevral '25
+187
3 kanalda
Get PRO
Yanvar '25
+129
53 kanalda
Get PRO
Dekabr '24
+148
0 kanalda
Get PRO
Noyabr '24
+123
0 kanalda
Get PRO
Oktabr '24
+448
43 kanalda
Get PRO
Sentabr '24
+643
252 kanalda
Get PRO
Avgust '24
+127
0 kanalda
Get PRO
Iyul '24
+191
54 kanalda
Get PRO
Iyun '24
+1 110
244 kanalda
Get PRO
May '24
+1 483
192 kanalda
Get PRO
Aprel '24
+706
22 kanalda
Sana
Obunachilarni jalb qilish
Esdaliklar
Kanallar
27 Oktabr+2
26 Oktabr0
25 Oktabr0
24 Oktabr+2
23 Oktabr0
22 Oktabr0
21 Oktabr+4
20 Oktabr+3
19 Oktabr+2
18 Oktabr+2
17 Oktabr+4
16 Oktabr+1
15 Oktabr+1
14 Oktabr+3
13 Oktabr+1
12 Oktabr+3
11 Oktabr+2
10 Oktabr+2
09 Oktabr+1
08 Oktabr+2
07 Oktabr0
06 Oktabr+2
05 Oktabr+3
04 Oktabr+2
03 Oktabr+1
02 Oktabr+1
01 Oktabr+5
Kanal postlari
🤔 Когда нужно объявлять деструктор виртуальным? Виртуальный деструктор нужен всегда, когда класс предполагается использовать в качестве базового и поддерживает полиморфизм (наследование и динамическое связывание). 🚩Зачем нужен виртуальный деструктор? Если у базового класса деструктор не виртуальный, а удаление происходит через указатель на базовый класс, деструктор производного класса не вызовется! Это приведёт к утечке памяти или некорректному освобождению ресурсов. Пример проблемы без виртуального деструктора
#include <iostream>

class Base {
public:
    ~Base() { std::cout << "Деструктор Base\n"; } // НЕ виртуальный!
};

class Derived : public Base {
public:
    ~Derived() { std::cout << "Деструктор Derived\n"; }
};

int main() {
    Base* obj = new Derived();
    delete obj; // Проблема! Деструктор Derived НЕ вызывается!
}
Вывод
Деструктор Base
🚩Решение: сделать деструктор виртуальным Если объявить деструктор базового класса виртуальным (virtual), то при удалении через указатель на базовый класс будет вызван полный цепной деструктор. Используем virtual
class Base {
public:
    virtual ~Base() { std::cout << "Деструктор Base\n"; } // Виртуальный!
};

class Derived : public Base {
public:
    ~Derived() { std::cout << "Деструктор Derived\n"; }
};

int main() {
    Base* obj = new Derived();
    delete obj; // Теперь вызываются оба деструктора
}
Вывод
Деструктор Derived
Деструктор Base
🚩Когда не нужно делать деструктор виртуальным? Когда класс не предназначен для наследования Например, std::vector, std::string, std::unique_ptr – у них нет виртуального деструктора, так как они не предполагают полиморфное использование Когда удаление всегда происходит по ссылке/указателю на сам класс, а не на базовый
   Derived* obj = new Derived();
   delete obj; // В любом случае вызовет правильный деструктор
Если класс "заморожен" (final)
   class FinalClass final {
   public:
       ~FinalClass() { std::cout << "Деструктор\n"; }
   };
Ставь 👍 и забирай 📚 Базу знаний

2
🎃 Хеллоуинская акция на easyoffer В честь Хеллоуина до 31 октября можно забрать PRO навсегда. Покупаешь один раз и пользуешь
🎃 Хеллоуинская акция на easyoffer В честь Хеллоуина до 31 октября можно забрать PRO навсегда. Покупаешь один раз и пользуешься всю жизнь 🍬Что внутри мешка с угощениями: – База вопросов и задач из собеседований – Примеры видео-ответов на вопросы – Записи реальных собеседований – Тренажёры «Проработка вопросов» и «Реальное собеседование» – Аналитика требований из вакансий – Автоотклики на вакансии 👉 Забрать PRO со скидкой 70%: https://easyoffer.ru/pro
213
3
🤔 Что известно о ключевом слове override? Ключевое слово override используется для явного указания, что метод переопределяет виртуальный метод базового класса. Оно предотвращает ошибки, связанные с неправильным именованием или сигнатурой методов. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚Базу знаний
283
4
🤔 Что можешь сказать про исключение в конструкторе? Если конструктор выбрасывает исключение, объект считается не созданным. Это означает, что деструктор вызываться не будет, но уже созданные части объекта могут потребовать очистки. 🚩Что происходит при исключении в конструкторе? Когда исключение возникает в конструкторе: Объект не создаётся – вызов конструктора считается неудачным. Деструктор НЕ вызывается – потому что объект не был полностью создан. Уже созданные члены класса должны быть очищены вручную (если используются RAII-объекты, они сами очистят ресурсы). Исключение должно быть обработано – либо перехвачено (try-catch), либо передано дальше. 🚩Пример исключения в конструкторе #include <iostream> #include <stdexcept> class MyClass { public: MyClass() { std::cout << "Конструктор\n"; throw std::runtime_error("Ошибка в конструкторе!"); } ~MyClass() { std::cout << "Деструктор\n"; } }; int main() { try { MyClass obj; // Попытка создать объект } catch (const std::exception& e) { std::cout << "Поймано исключение: " << e.what() << '\n'; } } Вывод программы Конструктор Поймано исключение: Ошибка в конструкторе! 🚩Как правильно работать с исключениями в конструкторе? 🟠Использовать RAII Лучший способ избежать утечек – использовать RAII (объекты, которые сами освобождают ресурсы в деструкторе). #include <iostream> #include <memory> #include <stdexcept> class MyClass { private: std::unique_ptr<int> data; // Умный указатель RAII public: MyClass() : data(std::make_unique<int>(42)) { throw std::runtime_error("Ошибка!"); } }; int main() { try { MyClass obj; } catch (const std::exception& e) { std::cout << "Ошибка: " << e.what() << '\n'; } } 🟠Использовать `try-catch` внутри конструктора Если важно, чтобы объект всегда создавался, можно перехватывать исключение прямо в конструкторе. class MyClass { public: MyClass() { try { throw std::runtime_error("Ошибка!"); } catch (...) { std::cout << "Ошибка обработана, объект создан\n"; } } }; 🟠Использовать `noexcept(false)` или `noexcept(true)` По умолчанию конструкторы могут выбрасывать исключения, но если мы точно знаем, что этого не произойдёт, лучше явно указать noexcept: class SafeClass { public: SafeClass() noexcept { std::cout << "Конструктор без исключений\n"; } }; Ставь 👍 и забирай 📚 Базу знаний
262
5
Как зарабатывать на мобильной игре Как привлекать пользователей, работать с монетизацией и развивать мобильную игру в 2026 го
Как зарабатывать на мобильной игре Как привлекать пользователей, работать с монетизацией и развивать мобильную игру в 2026 году? Обсудим вместе с экспертами игровой индустрии России на RuStore Mobile GameDev Conf. 2 ноября, Москва + онлайн. Участие бесплатное, по регистрации Зарегистрироваться #реклама 16+ rustore.ru О рекламодателе
310
6
🤔 Какая сложность операции вставки у list? Вставка в list имеет сложность O(1), так как требуется лишь обновление ссылок соседних узлов. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚Базу знаний
318
7
🤔 Для чего используется ключевое слово volatile? Используется для обозначения переменных, значение которых может изменяться неожиданно для компилятора. Это может происходить, например, из-за внешних факторов вне контроля программы, таких как аппаратные регистры, прерывания или многопоточные среды. volatile говорит компилятору, что он не должен оптимизировать код, касающийся этих переменных, и всегда должен считывать их значения непосредственно из памяти. 🚩Основные применения 🟠Аппаратные регистры Переменные, связанные с аппаратными устройствами, такими как порты ввода-вывода, часто меняются вне контроля программы. Использование volatile предотвращает оптимизации, которые могли бы кэшировать значение регистров. volatile int* port = reinterpret_cast<int*>(0x400); *port = 42; // Запись в аппаратный регистр 🟠Переменные, изменяемые прерываниями В системах реального времени и встроенных системах значения переменных могут изменяться в обработчиках прерываний. volatile гарантирует, что каждое обращение к такой переменной будет действительным. volatile bool interruptFlag = false; void interruptHandler() { interruptFlag = true; // Устанавливается в обработчике прерывания } void mainFunction() { while (!interruptFlag) { // Ожидание установки флага прерывания } // Обработка прерывания } 🟠Многопоточные приложения Переменные, которые могут изменяться из других потоков, также могут быть помечены как volatile. Однако следует отметить, что volatile не обеспечивает защиту от гонок данных и не заменяет средства синхронизации, такие как мьютексы или атомарные операции. volatile bool stopThread = false; void workerThread() { while (!stopThread) { // Выполнение работы } } int main() { std::thread t(workerThread); // ... stopThread = true; // Остановка рабочего потока t.join(); return 0; } 🚩Особенности и ограничения 🟠Оптимизация компиляции volatile предотвращает оптимизации компилятором, которые могли бы удалить или кэшировать доступы к переменной. 🟠Не потокобезопасность volatile не обеспечивает потокобезопасность. Для обеспечения корректной работы в многопоточной среде следует использовать мьютексы, атомарные операции или другие механизмы синхронизации. 🟠Совместное использование с `const` Переменные могут быть как const volatile, если они не должны изменяться программой, но могут изменяться внешними факторами. 🚩Пример: Аппаратные регистры #include <iostream> volatile int* hardwareRegister = reinterpret_cast<int*>(0x400); void writeToRegister(int value) { *hardwareRegister = value; // Запись в регистр } int readFromRegister() { return *hardwareRegister; // Чтение из регистра } int main() { writeToRegister(100); std::cout << "Register value: " << readFromRegister() << std::endl; return 0; } Ставь 👍 и забирай 📚 Базу знаний
293
8
🤔 Какой контейнер используется в priority_queue? priority_queue в C++ обычно реализован на базе std::vector с использованием кучи (heap) для управления приоритетами. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚Базу знаний
344
9
🤔 Как работает виртуальность в C++? Виртуальность позволяет осуществлять полиморфизм — важную концепцию объектно-ориентированного программирования, которая позволяет объектам производных классов быть обработанными через указатели или ссылки на базовый класс. Это достигается с помощью виртуальных функций, которые определяются в базовом классе и могут быть переопределены в производных классах. 🚩Виртуальные функции Виртуальная функция определяется в базовом классе с ключевым словом virtual. Производный класс может переопределить эту функцию. class Base { public: virtual void display() const { std::cout << "Display from Base" << std::endl; } }; class Derived : public Base { public: void display() const override { std::cout << "Display from Derived" << std::endl; } }; 🚩Как работает vtable и vptr 🟠vtable (виртуальная таблица) Это таблица указателей на виртуальные функции класса. Каждый класс, содержащий виртуальные функции, имеет свою собственную vtable. В vtable хранятся адреса функций, которые должны быть вызваны для объектов данного класса. 🟠vptr (указатель на vtable) Это скрытый указатель в каждом объекте класса, содержащего виртуальные функции. Он указывает на vtable соответствующего класса. Когда объект создается, vptr инициализируется, указывая на vtable его класса. #include <iostream> class Base { public: virtual void display() const { std::cout << "Display from Base" << std::endl; } virtual void show() const { std::cout << "Show from Base" << std::endl; } }; class Derived : public Base { public: void display() const override { std::cout << "Display from Derived" << std::endl; } }; int main() { Base* b = new Derived(); b->display(); // Вызовет Derived::display() благодаря vtable b->show(); // Вызовет Base::show() поскольку она не переопределена delete b; return 0; } 🚩Процесс вызова виртуальных функций 🟠При компиляции Компилятор создает vtable для каждого класса, содержащего виртуальные функции. Компилятор также добавляет скрытый vptr в каждый объект класса, который инициализируется для указания на соответствующую vtable. 🟠При выполнении Когда вызывается виртуальная функция через указатель или ссылку на базовый класс, программа использует vptr для доступа к vtable и вызова правильной версии функции. Это обеспечивает динамическое разрешение вызова функции (runtime polymorphism). 🚩Полиморфизм и наследование Полиморфизм позволяет использовать базовые указатели или ссылки для работы с производными объектами, что делает код более гибким и расширяемым. void callDisplay(const Base& obj) { obj.display(); } int main() { Base b; Derived d; callDisplay(b); // Вызовет Base::display() callDisplay(d); // Вызовет Derived::display() return 0; } Ставь 👍 и забирай 📚 Базу знаний
330
10
🤔 Какая сложность работы с кучей? Работа с кучей (heap) в алгоритмах обычно имеет временную сложность O(log n) для операций вставки и удаления, т.к. элементы необходимо сравнивать и переставлять для поддержания свойств кучи. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚Базу знаний
374
11
🤔 Что можешь сказать плохого про MVC? МVC (Model-View-Controller) – это классический паттерн разделения логики приложения, но у него есть недостатки, особенно в сложных проектах. 🚩Запутанные связи между компонентами Взаимодействие между Model, View и Controller может стать сложным. Когда модель изменяется, нужно обновлять все представления (View), которые её используют. Если контроллер слишком тесно связан с представлением, код становится сложно поддерживать. В сложных GUI-приложениях (например, Qt, MFC) модель может изменяться из разных мест, и контроллеру трудно управлять обновлениями. 🚩Слабая масштабируемость в больших проектах MVC не даёт чёткого разделения ответственности, если приложение очень сложное. Один контроллер может управлять сразу несколькими представлениями, что создаёт запутанный код. Часто приходится создавать "промежуточные" контроллеры для разруливания логики → код становится сложнее. В сложных веб-приложениях (React, Angular) MVC превращается в "спагетти", потому что представления (View) и контроллеры (Controller) начинают выполнять логические задачи, которые должны быть в модели. Использовать слоистую архитектуру (Layered Architecture) или Service Layer. 🚩"Толстый" контроллер (Fat Controller) Если бизнес-логика попадает в контроллер, он становится раздутым и сложно поддерживаемым. Контроллер начинает обрабатывать данные, проверять их, а не просто передавать управление. class UserController { public: void login(std::string username, std::string password) { if (username.empty() || password.empty()) { std::cout << "Ошибка: пустые данные\n"; return; } if (username == "admin" && password == "1234") { std::cout << "Вход выполнен!\n"; } else { std::cout << "Неверный логин/пароль\n"; } } }; Здесь контроллер сам проверяет данные и логику аутентификации, что нарушает принцип разделения ответственности (SRP). Вынести бизнес-логику в Model или Service. Использовать слоистую архитектуру (Service Layer, Repository Pattern). class AuthService { public: bool authenticate(const std::string& username, const std::string& password) { return (username == "admin" && password == "1234"); } }; class UserController { AuthService authService; public: void login(const std::string& username, const std::string& password) { if (authService.authenticate(username, password)) { std::cout << "Вход выполнен!\n"; } else { std::cout << "Неверный логин/пароль\n"; } } }; 🚩Трудности тестирования (особенно View и Controller) Model тестируется легко, потому что она "чистая" (без UI-кода). Controller и View сложно тестировать, потому что они зависят от пользовательского ввода и интерфейса. Unit-тестирование UI-кода практически невозможно, требуется мокирование. 🚩Не всегда подходит для многопоточных приложений В многопоточных приложениях несколько представлений могут обращаться к одной модели, вызывая гонки данных. Если контроллер один на несколько потоков, он становится "узким местом" (bottleneck). Ставь 👍 и забирай 📚 Базу знаний
365
12
🤔 Вызов function call для конструктора и деструктора? В C++ конструктор вызывается автоматически при создании объекта, а деструктор – при его уничтожении. Однако, если говорить о вызове конструктора и деструктора как function call (операция ()), то такой вызов невозможен напрямую, потому что конструкторы и деструкторы не являются обычными функциями. 🚩Вызов конструктора (function call) Конструктор вызывается только через создание объекта class A { public: A() { std::cout << "Конструктор A\n"; } }; int main() { A obj; // Автоматический вызов конструктора } Нельзя вызвать конструктор явно как функцию. Попытка вызвать конструктор напрямую приведет к ошибке A(); // ❌ Ошибка: нельзя вызвать конструктор как обычную функцию Можно вручную вызвать конструктор через placement new #include <iostream> #include <new> class A { public: A() { std::cout << "Конструктор A\n"; } ~A() { std::cout << "Деструктор A\n"; } }; int main() { char buffer[sizeof(A)]; // Выделяем сырую память под объект A* obj = new (buffer) A; // Вызываем конструктор вручную (placement new) obj->~A(); // Вызываем деструктор вручную return 0; } 🚩Вызов деструктора (function call) Деструктор вызывается автоматически при уничтожении объекта class A { public: ~A() { std::cout << "Деструктор A\n"; } }; int main() { A obj; // Деструктор вызовется автоматически при выходе из `main` } Можно вызвать деструктор вручную, но это редко нужно. Деструктор можно вызвать явно, используя ~ИмяКласса() A obj; obj.~A(); // Вызов деструктора вручную (обычно не нужен) Деструктор обязательно вызывается вручную при new. Если объект создается через new, то его нужно удалить вручную через delete, иначе будет утечка памяти: A* ptr = new A(); delete ptr; // Автоматически вызывает деструктор Вызов деструктора при placement new. Если объект создавался с placement new, то деструктор вызывается вручную char buffer[sizeof(A)]; A* obj = new (buffer) A; obj->~A(); // Явный вызов деструктора, так как delete не применяется Ставь 👍 и забирай 📚 Базу знаний
368
13
🤔 Когда выбросили исключение из конструктора, о чем стоит помнить? Если исключение выброшено из конструктора, деструктор объекта вызван не будет. Это требует ручного освобождения ресурсов, выделенных до момента выброса исключения. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚Базу знаний
410
14
🤔 Что будет если вызвать дважды lock()? Если вызвать дважды lock() на одном и том же объекте std::mutex из одного и того же потока, это приведет к взаимной блокировке (deadlock). Это происходит потому, что после первого вызова lock() мьютекс уже будет заблокирован данным потоком, и второй вызов lock() будет ожидать освобождения мьютекса, что никогда не произойдет, так как поток уже заблокировал мьютекс. #include <iostream> #include <thread> #include <mutex> std::mutex mtx; void threadFunction() { mtx.lock(); // Первый вызов lock() std::cout << "Locked once" << std::endl; // Попытка повторного захвата того же мьютекса приведет к взаимной блокировке mtx.lock(); // Второй вызов lock() - Deadlock std::cout << "Locked twice" << std::endl; mtx.unlock(); mtx.unlock(); } int main() { std::thread t(threadFunction); t.join(); return 0; } 🚩Как избежать взаимной блокировки 🟠Использование `std::recursive_mutex`: Этот тип мьютекса позволяет одному и тому же потоку захватывать мьютекс несколько раз без блокировки. Но следует использовать его осторожно, так как он может скрывать логические ошибки в коде. #include <iostream> #include <thread> #include <mutex> std::recursive_mutex rec_mtx; void threadFunction() { rec_mtx.lock(); // Первый вызов lock() std::cout << "Locked once" << std::endl; rec_mtx.lock(); // Второй вызов lock() std::cout << "Locked twice" << std::endl; rec_mtx.unlock(); rec_mtx.unlock(); } int main() { std::thread t(threadFunction); t.join(); return 0; } 🟠Использование `std::unique_lock` или `std::lock_guard`: Эти обертки автоматически управляют блокировкой и разблокировкой мьютекса, обеспечивая корректное использование мьютексов. #include <iostream> #include <thread> #include <mutex> std::mutex mtx; void threadFunction() { std::lock_guard<std::mutex> lock(mtx); // Автоматическая блокировка std::cout << "Locked once" << std::endl; // Повторный вызов lock() не требуется, так как lock_guard управляет мьютексом } int main() { std::thread t(threadFunction); t.join(); return 0; } 🟠Проверка состояния мьютекса с помощью `try_lock()`: Метод try_lock() пытается захватить мьютекс и возвращает false, если мьютекс уже захвачен, что предотвращает взаимную блокировку. #include <iostream> #include <thread> #include <mutex> std::mutex mtx; void threadFunction() { if (mtx.try_lock()) { // Попытка захвата мьютекса std::cout << "Locked once" << std::endl; if (mtx.try_lock()) { // Попытка повторного захвата std::cout << "Locked twice" << std::endl; mtx.unlock(); } mtx.unlock(); } } int main() { std::thread t(threadFunction); t.join(); return 0; Ставь 👍 и забирай 📚 Базу знаний
428
15
🔥 Скрытые вакансии с удаленной работой для C/C++ разработчика, которые нигде больше не публикуются. Напрямую от компаний, с
🔥 Скрытые вакансии с удаленной работой для C/C++ разработчика, которые нигде больше не публикуются. Напрямую от компаний, с контактами рекрутеров. 🔹 C/C++ Jobs | Вакансии 🔸 Все каналы с вакансиями
434
16
🤔 Как можно взвести бит используя побитовую операцию ИЛИ? Чтобы взвести (установить) бит в определённое значение (1) в числе, можно использовать побитовую операцию ИЛИ (|). Эта операция позволяет установить конкретный бит в 1, не изменяя остальные биты числа. 🚩Как это работает Операция ИЛИ (|) сравнивает каждый бит двух чисел. Если хотя бы один из битов в соответствующей позиции равен 1, результат в этой позиции будет 1. Иначе, результат будет 0. 🚩Шаги 1⃣Создаём маску, которая имеет единицу в позиции n и нули в остальных позициях. Это можно сделать с помощью выражения 1 << n. 2⃣Применяем операцию ИЛИ между числом x и маской. #include <iostream> int main() { int x = 0b00001010; // Число, с которым работаем (10 в десятичной системе) int n = 3; // Позиция бита, которую хотим установить (начиная с 0) // Создаём маску с единицей в позиции n int mask = 1 << n; // Устанавливаем бит в позиции n x = x | mask; // Вывод результата std::cout << "Результат: " << std::bitset<8>(x) << std::endl; // Двоичный вывод std::cout << "Результат: " << x << std::endl; // Десятичный вывод return 0; } 1 << n создает маску, сдвигая 1 влево на n позиций. Например, если n = 3, результат будет 0b00001000. Операция x | mask устанавливает бит в x на позиции n в 1. Если бит в x на позиции n уже был 1, он останется 1, если он был 0, то станет 1. 🚩Пример вывода Если x было 0b00001010 и n = 3, результат будет: Маска: 0b00001000 x | mask: 0b00001010 | 0b00001000 = 0b00001010 В результате бит в позиции 3 установлен в 1, и итоговое значение числа в двоичном формате 0b00001010 (десятичное 10). Ставь 👍 и забирай 📚 Базу знаний
529
17
🤔 Как можно проверить, что нет double exception? Используйте функцию std::uncaught_exceptions() (C++17) или std::uncaught_exception() (до C++17) для проверки активного исключения. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚Базу знаний
455
18
🤔 Когда при вызове exception не зовутся деструкторы? В C++ деструкторы объектов вызываются автоматически при выходе из области видимости, даже если выход происходит из-за исключения. Однако есть ситуации, когда деструкторы могут не вызваться, что может привести к утечке ресурсов. 🟠Динамически выделенные объекты (`new`) Если объект был создан с помощью new, но перед его удалением произошло исключение, деструктор не вызовется автоматически. #include <iostream> class A { public: A() { std::cout << "Конструктор A\n"; } ~A() { std::cout << "Деструктор A\n"; } }; void func() { A* obj = new A(); // Создаем объект динамически throw std::runtime_error("Ошибка!"); // Исключение, объект утечет delete obj; // Никогда не выполнится } int main() { try { func(); } catch (...) { std::cout << "Исключение поймано\n"; } } Как исправить? Использовать std::unique_ptr, который автоматически удаляет объект #include <memory> void func() { std::unique_ptr<A> obj = std::make_unique<A>(); throw std::runtime_error("Ошибка!"); // Деструктор вызовется автоматически } 🟠Локальные объекты, созданные `new` внутри `try`, но `catch` не обработал исключение Если объект выделяется внутри try, но исключение не ловится в catch, программа завершится (std::terminate), и деструкторы не вызовутся. void func() { A* obj = new A(); throw std::runtime_error("Ошибка!"); // std::terminate() delete obj; } int main() { func(); // Исключение не ловится => программа аварийно завершится } Как исправить? Нужно обрабатывать исключение на верхнем уровне int main() { try { func(); } catch (...) { std::cout << "Ошибка обработана\n"; } } 🟠Исключение в конструкторе Если исключение возникает в конструкторе, деструктор этого объекта не вызывается, но деструкторы уже созданных объектов будут вызваны. class B { public: B() { std::cout << "Конструктор B\n"; } ~B() { std::cout << "Деструктор B\n"; } }; class A { public: A() { std::cout << "Конструктор A\n"; throw std::runtime_error("Ошибка в конструкторе A"); } ~A() { std::cout << "Деструктор A\n"; } // Никогда не вызовется! }; int main() { try { B b; A a; // Исключение в конструкторе A } catch (...) { std::cout << "Исключение обработано\n"; } } Вывод Конструктор B Конструктор A Исключение обработано Деструктор B Как исправить? - Использовать концепцию "умные указатели" (std::unique_ptr), чтобы ресурсы очищались автоматически. - Переносить ресурсоемкие операции в отдельный метод (init()), который можно вызывать после конструктора. 🟠Исключение в деструкторе Если деструктор объекта бросает исключение, это опасно, особенно если исключение возникло в момент обработки другого исключения. class A { public: ~A() { std::cout << "Деструктор A\n"; throw std::runtime_error("Ошибка в деструкторе!"); // Ошибка } }; int main() { try { A a; throw std::runtime_error("Основное исключение"); } catch (...) { std::cout << "Исключение обработано\n"; } } Как исправить? Деструкторы не должны выбрасывать исключения. Если исключение возможно, его следует перехватывать внутри деструктора class A { public: ~A() { try { throw std::runtime_error("Ошибка в деструкторе!"); } catch (...) { std::cout << "Ошибка подавлена в деструкторе\n"; } } }; Ставь 👍 и забирай 📚 Базу знаний
466
19
🤔 В чем разница map и unordered_map? std::map и std::unordered_map – оба являются ассоциативными контейнерами в C++, но они устроены по-разному и имеют разные скорости работы. 🚩Как устроены контейнеры? 🟠`std::map` – красно-чёрное дерево (сбалансированное BST) Все ключи хранятся упорядоченно. Операции insert, erase, find выполняются за O(log n). Упорядоченность важна, если требуется поиск в диапазоне (lower_bound, upper_bound). #include <map> #include <iostream> int main() { std::map<int, std::string> m; m[2] = "B"; m[1] = "A"; m[3] = "C"; for (const auto& [key, value] : m) { std::cout << key << " -> " << value << '\n'; } } Вывод (отсортирован!) 1 -> A 2 -> B 3 -> C 🟠`std::unordered_map` – хеш-таблица Нет сортировки, но поиск выполняется быстро – O(1) (в среднем). Использует хеш-функцию, поэтому доступ к элементам зависит от хеширования. Может быть медленным при коллизиях (O(n) в худшем случае). #include <unordered_map> #include <iostream> int main() { std::unordered_map<int, std::string> um; um[2] = "B"; um[1] = "A"; um[3] = "C"; for (const auto& [key, value] : um) { std::cout << key << " -> " << value << '\n'; } } Вывод (порядок непредсказуем!) 2 -> B 1 -> A 3 -> C 🚩Когда использовать `map`, а когда `unordered_map`? 🟠Используйте `std::map`, если: Нужно сортированное хранение ключей. Требуется поиск по диапазону (lower_bound, upper_bound). Хеш-функция для ключей сложна или недоступна (например, std::pair без кастомного хешера). Ставь 👍 и забирай 📚 Базу знаний
460
20
🤔 Как работает счетчик у shared_ptr? Счетчик ссылок в `std::shared_ptr` увеличивается каждый раз, когда новый `shared_ptr` создается с указателем на объект, и уменьшается, когда `shared_ptr` уничтожается или перестает указывать на объект. Когда счетчик достигает нуля, объект уничтожается. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚Базу знаний
446