Для чего нужен enable_shared_from_this в C++
Что проверяют
Понимаете ли вы, откуда берётся двойное удаление при работе с shared_ptr и как объект может безопасно продлить собственную жизнь. Следом почти всегда спрашивают, можно ли вызвать shared_from_this() в конструкторе.
Как отвечать
Начните с проблемы. Объект, которым уже владеет shared_ptr, хочет отдать указатель на себя, например в колбэк. Если написать std::shared_ptr<T>(this), появится второй управляющий блок со своим счётчиком, и объект будет удалён дважды.
Решение:
- наследование: класс публично наследует
std::enable_shared_from_this<T>, внутри базы хранитсяweak_ptrна объект; - инициализация: этот
weak_ptrзаполняет конструкторshared_ptr(иstd::make_shared), когда видит нужную базу. Поэтому наследование должно быть публичным и однозначным, иначе база не будет обнаружена; shared_from_this(): возвращаетshared_ptr, который делит владение с существующими, счётчик общий;weak_from_this(): появился в C++17, отдаётweak_ptr, когда продлевать жизнь объекта не нужно.
Типичный сценарий: асинхронный код, например сессия в Boost.Asio. В обработчик захватывают auto self = shared_from_this();, и объект гарантированно доживает до завершения операции, даже если все внешние владельцы его отпустили.
С C++17 вызов shared_from_this() на объекте, которым не владеет ни один shared_ptr, бросает std::bad_weak_ptr. До C++17 это было неопределённое поведение.
Где спотыкаются
Вызывают shared_from_this() в конструкторе. В этот момент shared_ptr ещё не создан, внутренний weak_ptr пуст, и вызов бросит исключение.
Создают объект на стеке или держат в std::unique_ptr и зовут shared_from_this(). Наследование само по себе ничего не даёт, владеть объектом должен shared_ptr.
Сохраняют self внутри самого объекта, например в лямбде, которая хранится как член класса. Получается цикл владения, и объект не удалится никогда. Для таких мест берут weak_from_this() и проверяют результат lock().