智能指针是否可以处理下来,如果不是,解决此限制的安全方法是什么?
我正在尝试做的一个例子是有两个包含智能指针的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并仅使用downcast?还有其他解决方案吗?
答案 0 :(得分:5)
智能指针可以处理向下转换,但它不是自动的。并且获得const-correctness可能有点复杂(我在面试问题中使用了我们的智能指针实现,涉及一些模板技巧)。但是,许多智能指针的用户从未使用const限定类型实例化他们的智能指针。
你需要弄清楚的第一件事就是柜台。由于您可能需要在smart_ptr<Base>
和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>, ...
派生,因此,dynamic_cast<smart_ptr<T> >
将无效。您可以提供自己的smart_dynamic_cast<SPT>(smart_ptr<U> const& pU)
。这最好作为一个函数来实现SPT
。在此功能中,您只需执行return SPT(dynamic_cast<SPT::value_type*>(&*pU))
。
答案 1 :(得分: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,你应该从实现中学习。
答案 2 :(得分:1)
按照其中一个提升邮件列表中的主题here进行操作。它展示了如何在boost :: shared_ptr的情况下实现智能指针向下转换。 HTH
答案 3 :(得分:0)
正常的智能指针,如std::auto_ptr
,在STL容器中使用是不安全的,因为当STL在内部复制数据时,STL将智能指针的实例分配给彼此时所有权被移动。您需要使用类似boost::shared_ptr
的内容,它在内部实现引用计数,以确保对象保持活动状态,无论有多少智能指针实例引用它。如果您正在编写自己的智能指针类型,那么您需要实现类似的引用计数。
答案 4 :(得分:0)
我在Microsoft网页上找到了这个:
std::shared_ptr<base> sp0(new derived);
std::shared_ptr<derived> sp1 =
std::dynamic_pointer_cast<derived>(sp0);