复杂设计中的Shared_ptr和逻辑指针所有权用例

shared_ptr and logical pointer ownership use-case in a complex design

本文关键字:指针 所有权 ptr Shared 复杂      更新时间:2023-10-16

我有一个对象A,它包含一个共享资源(shared_ptr) r, Ar的创建者/所有者,在构建对象时,对象"注册"其r与另一个对象B。对象B在std::set中持有对Ar的引用。对象A用作Boost::asio::处理程序。

A被销毁时,我需要从B中注销r,当A拥有对r的唯一访问权时,因为Ar的创建者,它负责销毁它。注意:当A被用作boost::asio处理程序时,它的副本被构造多次。在这里保持唯一访问意味着没有asio操作发生(因为如果它们是引用计数将> 2,因为复制了A)。

目前r.use_count() == 2可以测试唯一访问,因为当没有异步操作发生时,A和B都可以访问对象。然而,我不认为这个测试在逻辑上是合理的。

我想我应该把B的容器从std::set<boost::shared_ptr<r> >改为std:set<boost::weak_ptr<r> >,这样当没有异步操作发生时,r.unique()在逻辑上是正确的。这是一个明智的使用weak_ptr ?

A (in_process_invoker)的构造函数和析构函数以及寄存器(connect)和unregister(disconnect)事件在我的代码中如下所示:

in_process_invoker(BackEnd & b_in)
  : client_data(new ClientData()),
    b(b_in),               
    notification_object(new notification_object_()) 
{
  b.connect(client_data);  
} 
~in_process_invoker()      
{
  if(client_data.unique()) 
  {
    b.disconect(client_data);       
  }
}

编辑

我更改了设计,使用原始指针,默认构造函数将调用者标记为主调用者,并将其副本标记为非主调用者。

如果您确定B持有的引用在A执行引用计数测试时仍然存在,那么为什么在B中使用任何类型的智能指针,为什么不使用原始指针?如果你不知道B仍然会保存一个引用,那么当前的== 2测试不仅是不明智的,而且是不正确的。

我看到的weak_ptr相对于原始指针的唯一优势是,如果您在将来更改内容,使A不会与B注销,因此引用可能会摆动,然后weak_ptr变得有用来告诉B发生了什么。这甚至可能不可能取决于B如何使用r:如果设计严重依赖于引用总是有效的事实,那么就没有必要放弃尝试来掩盖它不是的情况。

你可以在任何地方坚持使用shared_ptr,但是,如果A通过shared_ptr对代理对象持有对r的引用,而B通过shared_ptr直接持有对r的引用。然后让代理对象负责从B取消注册。这样,要销毁的A的最后一个副本将销毁代理,代理将注销B,然后销毁r。不需要任何人检查use_count

一个类似的选项是B持有一个原始指针,并让r在其析构函数中取消对B的注册。我不确定,使线程安全可能更难。

理想情况下,你应该使用"右"指针类型的所有权语义。如果B共同拥有r,那么它应该有一个shared_ptr,这样r就可以安全地超过A。如果B不拥有r,那么如果r在销毁之前可能不会从B注销,则使用weak_ptr(并确保Bweak_ptr过期时做正确的事情),或者如果B有其他人的保证以确保指针的有效性,则使用原始指针。

混合使用智能指针和原始指针是不安全的。的使用智能指针的全部意义在于找到一种方法来管理对象的回收,以及raw指针破坏了这一点,因为没有办法知道非null的原始指针是否有效。

你使用弱指针的解决方案对我来说似乎很合理——它清楚地区分了拥有和不拥有参考文献我已广泛使用在这种方法中,对象A被1所拥有另一个对象B,它将它保存到一个长期的共享指针,同样的对象A也是从任意数量的其他对象C-Z中引用通过弱指针。参考我对一个相关问题的回答:shared_ptr: what's it used for