在shared_ptr过期后查找weak_ptr

Locating a weak_ptr after shared_ptr is expired

本文关键字:ptr 查找 weak 过期 shared      更新时间:2023-10-16

我有一个结构体,A,其对象由shared_ptrs.结构A包含对结构B的引用。B对象需要跟踪哪些A对象包含对它们的引用,并且还需要能够向这些对象返回shared_ptr。为了简化这一点,我将一组weak_ptr存储到B中的关联A对象。目前为止,一切都好。

我的问题是我希望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 的集合并擦除任何过期的weak_ptrs,但这似乎并不干净。我也可以将B的设置转换为原始A指针,并在需要时使用这些原始指针访问 A 的shared_from_this(),但我不禁认为我只是做错了什么。

不要急切地从B::set_of_a中删除元素。当您lock访问对象的weak_ptr时,请检查它是否为 null,然后擦除。

你不能shared_from_this~A开始后,A已经停止了。

由于您没有提到编译器 - 如果您使用的是足够新的编译器,那么您可以使用weak_from_this(从 C++17 开始提供):

b.set_of_a.erase(weak_from_this());

这实际上会以干净的方式实现您想要的,因为那时您只需比较实际的weak_ptr实例,而不是尝试在 dtor 中创建新的共享实例,这在逻辑上现在失败了。似乎适用于 coliru,但在启用了 C++17 的 VS2017 (15.4.1) 上不起作用。

好奇的更新

此片段:

#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

关于科里鲁(GCC 8)。