std::shared_ptr хранит рядом с объектом control block — счётчик владельцев. Несколько shared_ptr безопасны, пока делят один control block. Проблема: иногда объекту нужно отдать shared_ptr на себя, но внутри метода есть только сырой this, который о counter'е ничего не знает.❌ Наивный способ:
struct S {
std::shared_ptr<S> self() { return std::shared_ptr<S>(this); }
};
auto p = std::make_shared<S>();
auto q = p->self();У
p и q свои control block'и, у каждого счётчик = 1 → объект удалится дважды (UB).✅ Решение — enable_shared_from_this:
struct S : std::enable_shared_from_this<S> {
std::shared_ptr<S> self() { return shared_from_this(); }
};
auto p = std::make_shared<S>();
auto q = p->self();База добавляет скрытый
weak_ptr<S>. При первом заворачивании в shared_ptr его конструктор замечает эту базу и кладёт туда свой control block. Теперь q разделяет счётчик с p.🍴 Что делает shared_from_this():
shared_ptr<S> shared_from_this() { return shared_ptr<S>(weak_this); }Это конструктор из
weak_ptr, а не lock(): без владельца он бросает bad_weak_ptr, а не молча возвращает пустой указатель.🍙 Когда скрытый weak_ptr пуст:
S s; // на стеке — никто не владеет
s.shared_from_this(); // 💥 bad_weak_ptr (до C++17 — UB)
struct T : std::enable_shared_from_this<T> {
T() { shared_from_this(); } // 💥 хук срабатывает после конструктора
};
Правила: наследовать публично, владеть через
shared_ptr (лучше make_shared). Нужна проверка без исключения — в C++17 есть weak_from_this():🍉 Правила:
• Наследуйте
enable_shared_from_this публично.• Владейте объектом через
shared_ptr — лучше make_shared (одна аллокация + exception-safety).• Не вызывайте
shared_from_this() в конструкторе и на объектах со стека — будет bad_weak_ptr.• Нужна проверка без исключения — в C++17 берите
weak_from_this():if (auto sp = obj.weak_from_this().lock()) { /* владелец есть */ }📍Навигация: Вакансии • Задачи • Собесы • Канал в Max
Библиотека C/C++ разработчика
#под_капотом