Пример ответа
Коротко: Я знаю и активно использовал в C++ следующие виды умных указателей: std::unique_ptr, std::shared_ptr, std::weak_ptr, а также, в рамках стандартной библиотеки, std::auto_ptr (устаревший).
- std::unique_ptr
- std::shared_ptr
- std::weak_ptr
- std::auto_ptr (устаревший)
Ключевые идеи:
- std::unique_ptr обеспечивает эксклюзивное владение ресурсом и перемещаемую семантику, идеален для управления единственным владельцем.
- std::shared_ptr реализует подсчёт ссылок для совместного владения, но требует осторожности из-за накладных расходов и риска циклических ссылок.
- std::weak_ptr используется вместе с shared_ptr для разрыва циклических зависимостей, не увеличивая счётчик ссылок.
Пример: В моём проекте для управления кэшем в памяти я использовал std::unique_ptr для эксклюзивного владения буферами данных и std::shared_ptr для разделяемых конфигурационных объектов между несколькими модулями, с weak_ptr для наблюдателей, чтобы избежать утечек памяти.
Пример использования std::unique_ptr и std::shared_ptr для управления ресурсами в C++
cpp
#include <memory>
#include <iostream>
class Resource {
public:
Resource() { std::cout << "Resource acquired\n"; }
~Resource() { std::cout << "Resource destroyed\n"; }
void use() { std::cout << "Resource in use\n"; }
};
int main() {
// std::unique_ptr: эксклюзивное владение
std::unique_ptr<Resource> uniquePtr = std::make_unique<Resource>();
uniquePtr->use();
// Перемещение владения
std::unique_ptr<Resource> movedPtr = std::move(uniquePtr);
if (!uniquePtr) {
std::cout << "uniquePtr is now null after move\n";
}
// std::shared_ptr: совместное владение
std::shared_ptr<Resource> sharedPtr1 = std::make_shared<Resource>();
{
std::shared_ptr<Resource> sharedPtr2 = sharedPtr1; // Счётчик ссылок увеличивается до 2
std::cout << "Use count inside scope: " << sharedPtr1.use_count() << '\n';
} // sharedPtr2 выходит из области видимости, счётчик уменьшается до 1
std::cout << "Use count outside scope: " << sharedPtr1.use_count() << '\n';
// std::weak_ptr: для наблюдения без владения
std::weak_ptr<Resource> weakPtr = sharedPtr1;
if (auto locked = weakPtr.lock()) {
locked->use();
std::cout << "Weak pointer successfully locked, use count: " << sharedPtr1.use_count() << '\n';
} else {
std::cout << "Resource no longer available\n";
}
return 0; // Ресурсы автоматически освобождаются
}
Вопросы для интервьюера:
- В каких сценариях вы предпочитаете std::unique_ptr над std::shared_ptr? — Я выбираю unique_ptr для ресурсов с единственным владельцем, таких как фабричные объекты или кэши, чтобы избежать накладных расходов на подсчёт ссылок и обеспечить чёткую семантику владения.
- Как вы избегаете циклических ссылок при использовании std::shared_ptr? — Я использую std::weak_ptr для ссылок, которые не должны увеличивать счётчик, например, в паттернах наблюдатель или кэшах, чтобы разорвать циклы и позволить корректное освобождение памяти.
Практический совет (на неделю):
- Начните с std::unique_ptr по умолчанию для управления ресурсами и переходите к shared_ptr только при необходимости совместного владения.
- Регулярно проверяйте код на наличие циклических ссылок с помощью инструментов вроде Valgrind или AddressSanitizer, особенно при интенсивном использовании shared_ptr.
C/C++ Backend
Общий
22%
Следующий: Есть ли военный билет
Предыдущий: Работаешь ли на данный момент