5

智能指针是否处理向下转换,如果不是,解决此限制的安全方法是什么?

我正在尝试做的一个示例是拥有两个包含智能指针的 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 并仅在使用时降低?还有其他解决方案吗?

4

5 回答 5

5

智能指针可以处理向下转换,但它不是自动的。并且获得 const 正确性可能有点复杂(我在面试问题中使用了我们的智能指针实现,其中涉及一些模板技巧)。但是,许多智能指针的用户从不使用 const 限定类型实例化他们的智能指针。

你需要得到正确的第一件事是计数器。由于您可能需要在smart_ptr<Base>and之间共享一个计数器smart_ptr<Derived>,因此计数器类型不应依赖于类型参数。总的来说,这没什么大不了的。计数器只是一个 size_t,可能包含在一个类中。(注意:有替代的智能指针设计,但问题强烈建议使用计数器)

对基地的演员应该是相当微不足道的。因此,您的 smart_ptr 应该有一个采用 smart_ptr 的构造函数。在这个ctor中,添加一行static_cast<T*>((U*)0);。这不会生成代码,但会在 T 不是 U 的基数(模 const 限定)时阻止实例化。

另一种方式应该是显式转换。您不能以编程方式枚举 T 的所有基数,因此smart_ptr<T>不能从smart_ptr<Base1_of_T>, smart_ptr<Base2_of_T>, ...因此派生,adynamic_cast<smart_ptr<T> >将不起作用。您可以提供自己的smart_dynamic_cast<SPT>(smart_ptr<U> const& pU). 最好将其实现为返回SPT. 在这个函数中,你可以简单地做一个return SPT(dynamic_cast<SPT::value_type*>(&*pU)).

于 2009-09-02T07:46:58.550 回答
2

您想要的属性是指向类型的协方差。也就是说,如果 D 是 B,那么你想要smartptr<D> isa smartptr<B>. 我不认为这在 C++ 中得到很好的支持,但一如既往,有模板/重载黑客可用。

http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/pointer_cast.html提供了适用于常规和 boost::smart_ptr 的动态转换。如果您不想只使用 Boost,则应该从实现中学习。

于 2009-09-02T00:42:21.767 回答
1

在 boost 邮件列表之一中关注此处的线程。它展示了在 boost::shared_ptr 的情况下如何实现智能指针向下转换。高温高压

于 2009-09-02T03:50:32.863 回答
0

普通的智能指针,比如std::auto_ptr,在 STL 容器中使用是不安全的,因为当 STL 在内部复制数据时,当 STL 将智能指针的实例相互分配时,所有权会被移动。您需要使用类似的东西boost::shared_ptr,它在内部实现引用计数以确保对象保持活动状态,无论有多少智能指针实例引用它。如果您正在编写自己的智能指针类型,那么您需要实现类似的引用计数。

于 2009-09-02T00:10:16.663 回答
0

我在 Microsoft 页面上找到了这个:

    std::shared_ptr<base> sp0(new derived); 
    std::shared_ptr<derived> sp1 = 
    std::dynamic_pointer_cast<derived>(sp0); 
于 2011-10-30T10:56:06.600 回答