How does one downcast a std::shared_ptr?
考虑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| struct SomethingThatsABase
{
virtual bool IsChildOne() const { return false; }
virtual bool IsChildTwo() const { return false; }
};
struct ChildOne : public SomethingThatsABase
{
virtual bool IsChildOne() const { return true; }
};
struct ChildTwo : public SomethingThatsABase
{
virtual bool IsChildTwo() const { return true; }
};
void SomeClientExpectingAChildOne(std::shared_ptr<ChildOne> const& ptrOne)
{
//Does stuff
}
void SomeClient(std::shared_ptr<SomethingThatsABase> const& ptr)
{
if (ptr->IsChildOne())
{
SomeClientExpectingAChildOne(ptr); //Oops.
//Hmm.. can't static_cast here, because we need a `shared_ptr` out of it.
}
} |
(请注意,我不能简单地执行std::shared_ptr(static_cast(ptr.get())),因为这样引用计数就不会在两个shared_ptr之间共享)
这应该起作用:
1 2 3 4
| if (ptr->IsChildOne())
{
SomeClientExpectingAChildOne(std::static_pointer_cast<ChildOne>(ptr));
} |
-
完善! +1。 (也许很快也会有"绿色弯角的东西")
-
+1-我没有意识到std::static_pointer_cast!这是如何工作的,返回的shared_ptr是否像代理一样工作,以便两个共享指针保持相同的引用计数左右?
-
@Frerich:shared_ptr有两个指针-一个指向共享对象,另一个指向具有强引用计数和弱引用计数的块。不同类型的两个shared_ptr可以毫无困难地共享强和弱参考计数块。我的猜测是使用static_pointer_cast是shared_ptr的friend来实现它,但是当然您的实现可能会有所不同。
-
我一直在Boost中使用shared_dynamic_cast。但是,显然dynamic_pointer_cast更通用,因为它可以与各种不同类型的指针(shared_ptr,原始指针,intrusive_ptr以及将来可能使用的其他任何类型)一起使用。
-
@ FrerichRaabe,@ billy-oneal,可能它使用aliasing constructor,(ref,ptr)创建ref的shared_pointer副本,但指向ptr。
static_cast的shared_ptr等效项是static_pointer_cast,dynamic_cast的shared_ptr等效项是dynamic_pointer_cast。
-
我没有意识到这两个方面,因此我去寻找一些文档。很酷的东西!
从C ++ 11开始,C ++标准的§20.10.2.2.9([util.smartptr.shared.cast])将std::shared_ptr的static_cast,const_cast和dynamic_cast等效项指定为如下:
std::static_pointer_cast:
1 2
| template <class T, class U>
shared_ptr< T > static_pointer_cast(shared_ptr<U> const & r) noexcept; |
static_pointer_cast要求static_cast(r.get())的格式正确。如果r为空,则返回空的shared_ptr< T >,否则返回与r共享所有权的指针w,其中w.get() == static_cast(r.get())和w.use_count() == r.use_count()。
std::const_pointer_cast:
1 2
| template <class T, class U>
shared_ptr< T > const_pointer_cast(shared_ptr<U> const & r) noexcept; |
const_pointer_cast与static_pointer_cast具有相似的要求和语义,不同之处在于,使用const_cast代替了static_cast。
std::dynamic_pointer_cast:
1 2
| template <class T, class U>
shared_ptr< T > dynamic_pointer_cast(shared_ptr<U> const & r) noexcept; |
dynamic_pointer_cast有点不同,因为它要求dynamic_cast(r.get())格式正确并具有明确定义的语义。如果dynamic_cast(r.get())是非零值,则返回与r共享所有权的指针w,其中w.get() == dynamic_cast(r.get())和w.use_count() == r.use_count(),否则返回空的shared_ptr< T >。
std::reinterpret_pointer_cast:
对于C ++ 17,N3920(于2014年2月加入图书馆基础知识TS中)也提出了与上述类似的std::reinterpret_pointer_cast,只要求reinterpret_cast((U *) 0)格式正确并返回shared_ptr< T >(r, reinterpret_cast::element_type *>(r.get()))即可。注意N3920还更改了其他shared_ptr强制转换的措辞,并扩展了shared_ptr以支持数组。