如何从shared_ptr中调用私有析构函数?

9
我有一个资源管理器(resource_manager)类,它在内部维护了一个std::vector< boost::shared_ptr< resource > >。resource_manager是resource的友元类。我希望只有resource_manager才能创建/删除resource,所以我将其构造函数设为private(这个方法可行)。
然而,如果我将析构函数设为private,代码就无法编译,因为boost::shared_ptr会调用析构函数,而它不是resource的友元类。我考虑通过只从resource_manager返回const resource*来强制实施“不要由客户端删除”的规则,但某种程度上我对该方法提供的安全性并不满意(如果客户端偶然发现了指向非const的指针怎么办?)
除了不使用shared_ptr的显而易见的解决方案外,您是否有任何解决问题的方法或更好的解决方案?

客户端莫名其妙地遇到了一个非常量指针,唯一能做到这一点的方法就是使用 const_cast 进行强制转换。从“安全”角度来看,原始指针和 shared_ptr 之间没有区别,区别在于生命周期管理,如果没有 shared_ptr ,我不确定您如何处理。 - ronag
4
一个 const resource* 并不意味着你不能删除它。 - UncleBens
@UncleBens:难道不行吗?我以为编译器不允许在const上调用非const的函数!我错了吗?或者这个规则不适用于析构函数? - Dan Nestor
1
这条规则不适用于析构函数,因为否则你将无法销毁被声明为 const 的对象。 - MSalters
2个回答

14

您可以向共享指针传递自定义的 deleter。因此,只需创建一个 deleter 函数或函数对象(由您决定),该函数对象作为您的类的 friend

class Secret
{
  ~Secret() { }
  friend class SecretDeleter;
  friend void SecretDelFunc(Secret *);
};

class SecretDeleter
{
public:
  void operator()(Secret * p) { delete p; }
};

void SecretDelFunc(Secret * p) { delete p; }

std::shared_ptr<Secret> sp1(new Secret, SecretDeleter());
std::shared_ptr<Secret> sp2(new Secret, SecretDelFunc);

1
顺便提一下,你应该实例化 SecretDeleter - Xeo
1
@Xeo:完成。我猜一个自由函数甚至比一个函数对象类更容易。我也会添加那个。(实际上,在C++11中,还有第三个奥秘选项,可以制作一个特殊的分配器,使其成为友元,然后使用std::allocate_shared。) - Kerrek SB
有没有比创建独立的删除对象和/或函数更少痛苦的方法。我想这是一个相当常见的习语。 - uuu777
@KerreK SB。我不知道你的经验如何。除了我之外,我们还有2000多名软件工程师,我希望(a)确保没有人可以在shared_ptr管理的对象上调用delete,(b)不为我编写的每个对象键入自定义删除器,以及(c)使用make_shared的性能和安全优势。也许这只适用于大型企业。 - uuu777
@Kerrek SB。所以你在实质上同意我的观点。现在谈谈使用“现代C ++”的实际影响。在任何真正的软件开发公司中,你没有机会了解99.9999%的真实错误。而且,除此之外,您也没有机会了解任何未被使用的功能上的任何真实错误,因为做出决策的人认为它是不必要的繁琐。这里没有什么新鲜事-喜欢设计c ++的人喜欢让他们的东西非常繁琐。 - uuu777
显示剩余3条评论

1
也许可以将 shared_ptr<resource> 声明为友元?shared_ptr 不会调用构造函数,只有在资源管理器在所有客户端销毁其 shared_ptrs 之前释放指针时才会析构。这不会允许客户端破坏保护,但会允许客户端违背资源管理器的意愿使资源保持活动状态。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接