在 shared_ptr 过期后定位 weak_ptr
Locating a weak_ptr after shared_ptr is expired
我有一个结构 A
,它的对象由 shared_ptr
管理。结构 A
持有对结构 B
的引用。 B
对象需要跟踪哪些 A
对象持有对它们的引用,并且还需要能够 return 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()
,但我忍不住想我只是做错事了。
由于您没有提到编译器 - 如果您使用的是足够新的编译器,那么您可以使用 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
在 coliru (gcc 8) 上。
不要急切地从 B::set_of_a
中删除元素。当你lock
weak_ptr
访问对象时,检查它是否为空,然后擦除。
你不能shared_from_this
在~A
开始之后,A
已经不复存在了。
我有一个结构 A
,它的对象由 shared_ptr
管理。结构 A
持有对结构 B
的引用。 B
对象需要跟踪哪些 A
对象持有对它们的引用,并且还需要能够 return 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()
,但我忍不住想我只是做错事了。
由于您没有提到编译器 - 如果您使用的是足够新的编译器,那么您可以使用 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
在 coliru (gcc 8) 上。
不要急切地从 B::set_of_a
中删除元素。当你lock
weak_ptr
访问对象时,检查它是否为空,然后擦除。
你不能shared_from_this
在~A
开始之后,A
已经不复存在了。