您有两个类Animal
和Dog
(其中Dog
继承自Animal
),并且您有一种情况,您经常期待一只动物,但却发送了一只狗的实例。在我的特殊情况下,我经常将强指针(std::shared_ptr<Dog>
)转换为动物期望函数(std::shared_ptr<Animal>
)。
如果我们接受我们可以使函数参数成为引用(std::shared_ptr<Animal>&
,避免参数,为什么你不应该有强指针作为引用参数,因为担心改变线程的所有权),我认为我们将是安全的内存明智的转换std::shared_ptr<Dog> dog
使用reinterpret_cast<std::shared_ptr<Animal>&>(dog)
,对吗?
如果是这样,除了线程问题还会出现什么?比如参考计数品种?
要清楚,目的是有一个解决方案,将在许多情况下使用,一次强制转换不是一个真正可行的解决方案。更重要的是,有很多对象需要被投射。此外,忽略std::unique_ptr
可能是也可能不是更好的解决方案。
添加最后一个要求-使用普通指针将不允许我在通用序列化器类函数是虚拟的情况下更改原始std::shared_ptr
,因此不能被模板化
由于不可能直接在std::shared_ptr
上使用static_cast
, const_cast
, dynamic_cast
和reinterpret_cast
来检索与作为参数传递的指针共享所有权的指针,因此应该使用std::static_pointer_cast
, std::const_pointer_cast
, std::dynamic_pointer_cast
和std::reinterpret_pointer_cast
函数。
std::reinterpret_pointer_cast
在c++ 11和c++ 14中不可用,因为它仅由N3920提出,并于2014年2月被采纳到Library Fundamentals TS中。但是,它可以这样实现:
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())); }
我经常将强指针(
std::shared_ptr<Dog>
)转换为动物期望函数(std::shared_ptr<Animal>
)。
不需要强制类型转换(即显式转换)。指向派生类型的共享指针可隐式转换(1)为指向基类的共享指针。
(a)如果我们接受可以使函数形参成为引用
如果满足一些要求,我们只能接受这个假设。首先,函数不能将引用的实参存储在函数作用域之外(复制除外)。其次,作为引用传递的指针必须是本地指针或临时指针,如果不是,则函数不得调用任何可以直接或间接访问被引用指针的函数。
还应考虑,如果引用是非const,则不能依赖隐式转换(1)。相反,必须创建一个正确类型的单独共享指针(可以使用隐式转换创建它并传递它)。const引用形参或非引用形参就没有这个问题。
(b)我认为我们将是安全的内存明智的转换std::shared_ptr狗使用
reinterpret_cast<std::shared_ptr<Animal>&>(dog)
,对吗?
标准方面,您建议的cast是不安全的-它具有未定义的行为。我不明白假设(b)是如何从假设(a)推导出来的。
如果在您的情况下使用shared_ptr的引用作为参数是可以的,但是由于转换(派生到基,非const到const),您无法避免refcounter的自增/自减,我建议使用裸指针作为参数。