智能指针是否可以处理向下转换,如果不是,那么解决此限制的安全方法是什么?
我想做的一个例子是拥有两个包含智能指针的 STL 向量(例如)。第一个包含指向基类的智能指针,而第二个包含指向派生类的智能指针。智能指针被引用计数,例如与Boost的shared_ptrs类似的行为,但是手动滚动。我提供了一些示例代码来提供示例:
vector<CBaseSmartPtr> vecBase;
vector<CDerivedSmartPtr> vecDer;
...
CBaseSmartPtr first = vecBase.front();
vecDer.push_back(CDerivedSmartPtr(dynamic_cast<CDerived*>(first.get()));
这对我来说似乎不安全,因为我认为我最终会得到两个管理同一个对象的智能指针。在某个时刻,这可能会导致其中一个释放该对象,而另一个仍然保留对该对象的引用。
我希望但不认为会起作用的是直接向下转换,同时保留相同的对象,例如
dynamic_cast<CDerivedSmartPtr>(first)
我是否应该考虑更改第二个容器以也使用 CBaseSmartPtr 并仅在使用时向下转换?还有其他解决方案吗?
Do smart pointers handle down casting, and if not what is a safe way of working around this limitation?
An example of what I'm trying to do is having two STL vectors (for example) containing smart pointers. The first contains smart pointers to a base class while the second contains smart pointers to a derived class. The smart pointers are referenced counted, e.g. similar behaviour to Boost's shared_ptrs, but hand-rolled. I've included some sample code that I whipped up to provide an example:
vector<CBaseSmartPtr> vecBase;
vector<CDerivedSmartPtr> vecDer;
...
CBaseSmartPtr first = vecBase.front();
vecDer.push_back(CDerivedSmartPtr(dynamic_cast<CDerived*>(first.get()));
This seems not safe to me, as I think I'm ending up with two smart pointers managing the same object. At some point down the track this is probably going to result in one of them freeing the object while the other still holds references to it.
What I'd hope for but don't think will work is a straight down-cast while keeping the same object, e.g.
dynamic_cast<CDerivedSmartPtr>(first)
Should I be looking to change the second container to also use CBaseSmartPtr and downcast on usage only? Are there other solutions?
发布评论
评论(5)
智能指针可以处理向下转型,但它不是自动的。获得常量正确性可能有点复杂(我在面试问题中使用了我们的智能指针实现,其中涉及一些模板技巧)。但许多智能指针的用户无论如何都不会用 const 限定类型实例化他们的智能指针。
您需要纠正的第一件事是计数器。由于您可能需要在
smart_ptr
和smart_ptr
之间共享计数器,因此计数器类型不应依赖于类型参数。一般来说,这无论如何也不是什么大不了的事。计数器只是一个 size_t,可能包装在一个类中。 (注意:还有其他智能指针设计,但问题强烈表明使用了计数器)向基数的强制转换应该相当简单。因此,您的 smart_ptr 应该有一个采用 smart_ptr 的构造函数。在此构造函数中,添加一行
static_cast((U*)0);
。这不会生成代码,但会在 T 不是 U 的基数(模 const 限定)时阻止实例化。相反,应该是显式强制转换。您无法以编程方式枚举 T 的所有基数,因此; > 不起作用。您可以提供自己的
smart_ptr
无法从smart_ptr, smart_ptr, ...
派生,因此,<代码>dynamic_castsmart_dynamic_cast(smart_ptr const& pU)
。最好将其实现为返回SPT
的函数。在此函数中,您可以简单地执行return SPT(dynamic_cast(&*pU))
。Smart pointers can handle downcasting, but it's not automatic. And getting const-correctness in can be a bit complex (I've used our smart pointer implementation in interview questions, there's some template trickery involved). But many users of smart pointers never instantiate their smart pointers with const-qualified types anyway.
The first thing you need to get correct is the counter. Since you may need to share a counter between
smart_ptr<Base>
andsmart_ptr<Derived>
, the counter type should not depend on the type argument. In general, this is not a big deal anyway. A counter is merely a size_t, probably wrapped in a class. (Note: there are alternative smart pointer designs, but the question strongly suggests a counter is used)A cast towards base should be fairly trivial. Hence, your smart_ptr should have a constructor taking a smart_ptr. In this ctor, add a line
static_cast<T*>((U*)0);
. This doesn't generate code, but prevents instantiation when T is not a base of U (modulo const qualifications).The other way around should be an explicit cast. You can't programatically enumerate all bases of T, so
smart_ptr<T>
cannot derive fromsmart_ptr<Base1_of_T>, smart_ptr<Base2_of_T>, ...
Hence, adynamic_cast<smart_ptr<T> >
won't work. You can provide your ownsmart_dynamic_cast<SPT>(smart_ptr<U> const& pU)
. This is best implemented as a function returing anSPT
. In this function, you can simply do areturn SPT(dynamic_cast<SPT::value_type*>(&*pU))
.您想要的属性是指向类型的协方差。也就是说,如果 D 是 B,那么您需要
smartptr isa smartptr
。我认为这在 C++ 中根本没有得到很好的支持,但一如既往,有可用的模板/重载 hack。http://www.boost.org/doc/libs/ 1_39_0/libs/smart_ptr/pointer_cast.html 提供了适用于常规和 boost::smart_ptr 的动态转换。如果您不想只使用 Boost,您应该从实现中学习。
The property you want is covariance in the pointed-to type. That is, if D isa B, then you want
smartptr<D> isa smartptr<B>
. I don't think this is elegantly supported at all in C++, but as always, there are template/overload hacks available.http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/pointer_cast.html gives a dynamic cast that works on regular and boost::smart_ptr. You should learn from the implementation if you don't want to just use Boost's.
请关注 boost 邮件列表之一此处的主题。它展示了如何在 boost::shared_ptr 的情况下实现智能指针向下转型。华泰
Follow the thread here in one of the boost mailing lists. It shows how one can implement smart-pointer downcasting in case of boost::shared_ptr. HTH
普通智能指针(如 std::auto_ptr)在 STL 容器中使用并不安全,因为当 STL 在内部复制数据时将智能指针实例相互分配时,所有权会发生移动。您需要使用类似
boost::shared_ptr
的东西,它在内部实现引用计数以确保对象保持活动状态,无论有多少智能指针实例引用它。如果您正在编写自己的智能指针类型,那么您需要实现类似的引用计数。Normal smart pointers, like
std::auto_ptr
, are not safe to use in STL containers, due to ownership being moved around when the STL assigns instances of smart pointers to each other as it copies data around internally. You need to use something likeboost::shared_ptr
instead, which internally implements reference counting to ensure an object stays alive no matter how many smart pointer instances refer to it. If you are writing your own smart pointer types, then you need to implement similar reference counting.我在微软页面上找到了这个:
I've found this on Microsoft pages: