【发布时间】:2021-05-23 13:58:17
【问题描述】:
我有一个类Inner,它应该唯一归类Outer所有,具体来说,除了Outer之外,没有人应该能够摧毁Inner,或者让它活着。
但是,我希望其他类 Consumers,可能存在于其他线程上,能够引用 Inner 并与它交互,只要它存在,当它最终死亡时,这些其他类只知道停止与Inner 互动。
换句话说,我想要Inner 的唯一所有权,但非唯一的生命周期限制访问。
理论上,这里的完美解决方案似乎是:
class Inner {
...
};
class Outer {
std::unique_ptr<Inner> unique_inner_;
std::weak_ptr<Inner> GetWeakInnerForConsumers() {...}
};
class Consumer {
Consumer(std::weak_ptr<Inner> weak_inner) : weak_inner_(weak_inner) {}
std::weak_ptr<Inner> weak_inner_;
};
但是这里的问题是你不能从 std::unique_ptr 创建一个弱指针,所以我不走运。
另一种方法是:
- 让
Inner继承自std::enable_shared_from_this<Inner>甚至 尽管Inner的唯一实例归std::unique_ptr所有 - ...并介绍
std::weak_ptr<Inner> GetWeakPtr() {return std::weak_ptr<Inner>(shared_from_this())}
...但是上面的方法似乎不起作用,因为shared_from_this() 似乎在Inner 是唯一拥有的时候抛出异常,这是完全合理的。即使它确实有效,我认为它也可能容易受到竞争的影响,因为weak_ptr::lock() 显然不能保持unique_ptr 活着。
所以考虑到这一切,我只能想出两个解决方案:
- 让
Outer维护一个std::shared_ptr<Inner>,并记录一下尽管有成员,Outer实际上是唯一的所有者这一事实,并确保没有人获得对Inner的强烈引用。这似乎是获胜的选择。或者... - 代替上面的,分发原始的
Inner*指向所有Consumers的指针,但是Consumer继承自class Inner::Observer,所以Consumer可以观察Inner的破坏,并保持一些状态以便它知道其到Inner*的原始 ptr 何时“过时”。这似乎没问题,但可能容易受到原始 ptr 访问和破坏观察之间的竞争的影响
上面的第一个选择是我唯一的选择吗?是否有其他方法可以实现唯一所有权但非唯一线程安全的弱访问?
【问题讨论】:
-
你的问题是不是无法解决?如果一个线程拥有销毁对象的不受约束的权利,那么另一个线程可能会检查该对象是否处于活动状态,开始对其进行处理,但在此过程中,该对象可能会死亡,并且您将获得 UB。跨度>
-
我也是这么想的。我想如果由于弱指针需要是线程安全的,它可以在使用时 暂时 保持 unique_ptr 活动,那将是理想的,但这不是真实存在的东西,也不应该它...我真的只是想防止分发对
Inner的长期强引用,但我可以分发weak_ptrs,它可以在使用它的短期内暂时保持底层对象的活动状态,但我认为不存在这样的概念:) -
一旦您在
weak_ptr上调用lock,您就请求拥有该对象的所有权,如果不请求所有权,您就不能使用weak_prt所引用的对象。所以到那时Outer不能再成为唯一的所有者了。 -
我知道,看我上面的评论。我认为我的问题格式不正确
-
that can temporarily keep the underlying object alive throughout the short-term period好吧,这仍然意味着它在该时间段内请求所有权(以使其保持活力)。这就是所有权的意义所在。
标签: c++ shared-ptr unique-ptr lifetime weak-ptr