C++ reinterpret_cast of std::shared_ptr 参考优化

C++ reinterpret_cast of std::shared_ptr reference to optimize

您有两个 classes AnimalDog(其中 Dog 继承自 Animal),并且您经常遇到这样的情况期待一只动物,但正在发送一只狗的实例。在我的特殊情况下,我经常将强指针 (std::shared_ptr<Dog>) 投射到动物预期函数 (std::shared_ptr<Animal>)。

如果我们接受我们可以使函数参数成为一个引用(std::shared_ptr<Animal>&,避免争论为什么你不应该有强指针作为引用参数,因为担心改变线程的所有权),我假设我们在内存方面使用 reinterpret_cast<std::shared_ptr<Animal>&>(dog) 来转换 std::shared_ptr<Dog> dog 是安全的,对吧?

如果是这样,除了线程问题之外还会出现什么问题;比如引用计数类的?

需要明确的是,我们的目的是要有一个可以在许多情况下使用的解决方案,其中强制转换一次并不是真正可行的解决方案。更重要的是,有许多对象必须投射。此外,忽略 std::unique_ptr 可能是也可能不是更好的解决方案。

添加最后一个要求 - 在通用序列化器 class 函数是虚拟的情况下,使用普通指针不允许我更改原始 std::shared_ptr,因此无法进行模板化。

I am often casting a strong pointer (std::shared_ptr<Dog>) to an animal-expecting function (std::shared_ptr<Animal>).

无需转换(即显式转换)。派生类型的共享指针可隐式转换 (1) 为基 class.

的共享指针

(a) If we accept that we can make the function parameter a reference

只有在满足一些要求的情况下,我们才能接受这个假设。首先,函数不得将引用的参数存储在函数范围之外(复制除外)。其次,作为引用传递的指针必须是本地指针或临时指针 - 如果不是,则该函数不得调用任何可以直接或间接访问引用指针的函数。

还要考虑如果引用是非常量,则不能依赖隐式转换 (1)。相反,您必须创建一个单独的正确类型的共享指针(您可以使用隐式转换来创建它并传递它。const 引用参数或非引用参数没有这个问题。

(b) I assume we would be safe memory-wise to cast a std::shared_ptr dog using reinterpret_cast<std::shared_ptr<Animal>&>(dog), right?

在标准方面,您建议的转换并不安全 - 它具有未定义的行为。我看不出假设 (b) 是如何从假设 (a) 推导出来的。


如果在你的情况下使用对 shared_ptr 的引用作为参数是可以的,但是由于转换(派生到基数,非 const 到 const)你无法避免引用计数器的 increment/decrement ,我建议改用裸指针作为参数。

因为无法在 std::shared_ptr 上直接使用 static_castconst_castdynamic_castreinterpret_cast 来检索与指针共享所有权的指针作为参数传递时,应使用 std::static_pointer_caststd::const_pointer_caststd::dynamic_pointer_caststd::reinterpret_pointer_cast 函数。

std::reinterpret_pointer_cast 在 C++11 和 C++14 中不可用,因为它仅由 N3920 and adopted into Library Fundamentals TS in February 2014 提出。不过可以这样实现:

template <typename To, typename From>
inline std::shared_ptr<To> reinterpret_pointer_cast(
    std::shared_ptr<From> const & ptr) noexcept
{ return std::shared_ptr<To>(ptr, reinterpret_cast<To *>(ptr.get())); }