Поиск слабого_потора после истечения срока действия shared_ptr
У меня есть структура, A
объекты которого управляются shared_ptr
s. Struct A
содержит ссылку на структуру B
, B
объекты должны отслеживать, какие A
объекты содержат ссылки на них, а также должны иметь возможность вернуть shared_ptr
с этими объектами. Чтобы сделать это легко, я храню набор weak_ptr
с ассоциированным A
объекты внутри B
, Все идет нормально.
Моя проблема в том, что я хочу A
Деструктор для удаления ссылки на себя из своей привязанной B
объект. Однако (то, что я думал, было) очевидное решение не работает, как к тому времени A
деструктор называется, его связывают weak_ptr
срок действия истек, что затрудняет удаление из набора. Вот что я попробовал:
#include <memory>
#include <set>
struct A;
struct B;
struct B{
std::set<std::weak_ptr<A>, std::owner_less<std::weak_ptr<A>>> set_of_a;
};
struct A : std::enable_shared_from_this<A>{
B &b;
A(B &b):b(b){};
~A(){
// bad_weak_ptr exception here
b.set_of_a.erase(shared_from_this());
}
};
int main(){
B b;
std::shared_ptr<A> a1 = std::make_shared<A>(b);
b.set_of_a.insert(a1);
{
std::shared_ptr<A> a2 = std::make_shared<A>(b);
b.set_of_a.insert(a2);
}
return 0;
}
Как правильно это сделать? Я мог бы просто иметь A
деструктор запускает набор B и удаляет все просроченные версии файлаугирых, но это не кажется чистым. Я также мог бы просто конвертировать B
настроен на сырье A
указатели и использовать эти необработанные указатели для доступа к shared_from_this()
когда нужно, но я не могу не думать, что просто делаю что-то не так.
2 ответа
Поскольку вы не упомянули компилятор - если вы используете достаточно новый компилятор, вы можете использовать weak_from_this (доступно из C++17):
b.set_of_a.erase(weak_from_this());
Это на самом деле достигнет того, что вы хотите, чистым способом, так как тогда вы просто будете сравнивать фактические weak_ptr
экземпляры вместо того, чтобы пытаться создать новый общий экземпляр в dtor, который теперь логически не работает. Кажется, работает на coliru, но не работает на VS2017 (15.4.1) с включенным C++ 17.
Обновление для любопытных
Этот фрагмент:
#include <memory>
#include <set>
#include <iostream>
struct A;
struct B;
struct B{
std::set<std::weak_ptr<A>, std::owner_less<std::weak_ptr<A>>> set_of_a;
};
struct A : std::enable_shared_from_this<A>{
B &b;
A(B &b):b(b){};
~A(){
b.set_of_a.erase(weak_from_this());
std::cout << "Size of set_of_a: " << b.set_of_a.size() << "\n";
}
};
int main(){
B b;
std::shared_ptr<A> a1 = std::make_shared<A>(b);
b.set_of_a.insert(a1);
{
std::shared_ptr<A> a2 = std::make_shared<A>(b);
b.set_of_a.insert(a2);
}
return 0;
}
дает вывод:
Size of set_of_a: 1
Size of set_of_a: 0
на колиру (гкц 8).
Не беспокойтесь, стирая элементы из B::set_of_a
, Когда ты lock
weak_ptr
чтобы получить доступ к объекту, проверьте, является ли он нулевым, и удалите его.
Ты не можешь shared_from_this
после ~A
началось, A
перестало быть.