自定义 std::shared_ptr 或 boost::shared_ptr 以在 NULL 取消引用时引发异常

Customising std::shared_ptr or boost::shared_ptr to throw an exception on NULL dereference

本文关键字:ptr shared 引用 异常 取消 boost std 自定义 以在 NULL      更新时间:2023-10-16

我有几个广泛使用boost::shared_ptrstd::shared_ptr的项目(我可以很快转换为任何一个实现,如果这个问题有一个很好的答案,但另一个没有)。 Boost 实现使用 Boost.Assert 来避免在运行时遇到空 (NULL) 指针或operator->operator*时返回;虽然libc ++实现似乎缺乏任何检查。

当然,在使用前应该检查shared_ptr的有效性,但大型的混合范式代码库使我想尝试一种抛出异常的变体;因为大多数代码都是相对异常感知的,最多会失败到高级但可恢复的状态,而不是std::terminate()或段错误。

我应该如何最好地自定义这些访问器,同时保持shared_ptr的健壮性? 似乎将shared_ptr封装在throwing_shared_ptr中可能是最好的选择,但我对打破魔法持谨慎态度。 我最好复制 Boost 源并将ASSERT更改为适当的throw语句吗?


在任何地方用于相应smart_ptr<T>类型的实际类型名称是从宏扩展的typedef;即ForwardDeclarePtr(Class)扩展为如下所示的内容:

class Class;
typedef boost::smart_ptr<Class> ClassPtr;

一切都通过、获取或存储ClassPtr- 所以我可以非常自由地替换底层类型;我怀疑这减轻了潜在的切片/隐藏问题。

如果您将其包装在自定义类中,std::shared_ptr<T>中实际上没有任何"魔法"会被删除,该自定义类在取消引用NULL共享指针时会引发异常。 所以我不明白为什么这种方法不起作用,只要你的新包装类遵循std::shared_ptr<T>类型的所有语义。

顺便说一句,你也可以采取稍微不同的方法,那就是创建一个包装类,它根本不允许其他人首先将NULL指针传递给包装的std::shared_ptr<T>数据成员。 基本上,它将是一个在其构造函数中强制执行std::make_shared<T>习惯用法的类。 我不确定,根据您的代码的工作方式,如果这是可能的,但这是使用 RAII 方法而不是抛出异常来规避问题的另一种方法。

只需将子类std::shared_ptrthrowing_shared_ptr中,覆盖这两个方法,并让它们断言并调用std::shared_ptr的 impl。只要您在任何地方使用throwing_shared_ptr而不是将其切成std::shared_ptr,这应该可以正常工作。