使用共享指针在两个类型模板化的类之间进行转换

时间:2013-08-31 14:33:23

标签: c++ casting type-conversion smart-pointers reinterpret-cast

我有一个像这样的图书馆提供的课程:

template <typename T>
class TypedClass
{
public:
    typedef typename boost::shared_ptr<TypedClass<T> > Ptr;

    T m_data;
    T* m_pointer_data;
};

假设我愿意接受int和float在这个特定架构上总是相同的大小(和对齐),这似乎对我有用:

TypedClass<int>* int_object = new TypedClass<int>();

TypedClass<float>* float_object = reinterpret_cast<TypedClass<float>* >(int_object);

现在我正在尝试使用boost shared_ptrs实现相同的功能,并提出了这个问题:

TypedClass<int>::Ptr int_object = TypedClass<int>::Ptr(new TypedClass<int>());

void* int_object_void_pointer = reinterpret_cast<void*>(int_object.get());

TypedClass<float>::Ptr float_object(reinterpret_cast<TypedClass<float>*>(int_object_void_pointer));

哪个似乎工作正常,但这种共享指针的使用会导致对象被删除两次,这是我想避免的。

重要的是要注意'TypedClass'是第三方库的一部分,并且该库使用共享指针来实现它的所有内部功能,所以我需要这种形式的数据。我之前已经解决了从boost enable_shared_from_this继承的问题,但这不可能。

这是一种尝试为具有相同大小的数据类型重用相同对象而不必使用新类型分配新对象的简单技术。

建议欢迎。

5 个答案:

答案 0 :(得分:6)

shared_ptr<T>有一个有趣的重载构造函数:

template<class Y> shared_ptr(shared_ptr<Y> const & r, element_type * p);

基本上这构造了一个shared_ptr,它从r获取删除和引用计数,但它保留p

你可以像这样使用它:

TypedClass<int>::Ptr int_object = TypedClass<int>::Ptr(new TypedClass<int>());

TypedClass<float>::Ptr float_object(int_object,reinterpret_cast<TypedClass<float>*>(int_object.get()));

修改

如果您使用的是Boost&gt; = 1.53.0,则还有boost::reinterpret_pointer_cast。所以你可以写:

TypedClass<float>::Ptr float_object = boost::reinterpret_pointer_cast<TypedClass<float> >(int_object);

答案 1 :(得分:1)

如果您确实尝试将相同对象重用于具有相同大小的数据类型而无需从第三方库分配具有新类型的新对象,则您的选择有限: / p>

  1. 您不应该从原始指针分配shared_ptr,否则会被删除两次,导致段错误;
  2. 您要么重用类型(shared_ptr),以便可以通过operator =()直接“复制”;或者使用原始指针,并确保不做影响内存分配/删除的更改。
  3. 作为您的示例,我建议使用以下代码:

    float* float_ptr = reinterpret_cast<float*>(&int_object->m_data);
    // Do something with *float_ptr
    // And never delete it!
    

答案 2 :(得分:1)

您可以使用boost pointer cast。这是一个非常难看的解决方案,但至少引用计数将以这种方式工作。

TypedClass<int>::Ptr int_object = TypedClass<int>::Ptr(new TypedClass<int>());
TypedClass<float>::Ptr float_object = boost::static_pointer_cast<TypedClass<float>>(boost::shared_ptr<void>(int_object));

答案 3 :(得分:0)

我认为你不能除了你用两个参数typename重载共享ptr类本身,因为它保持对数据的引用并在count为0时删除。但是你必须从一个类型转到另一个,boost shared ptr,会认为你还是发布了数据。

shared_ptr p = ptr; //如果ptr和p属于同一类型,则添加一个ref。

如果类型不相同,则检索内部数据然后将其释放。

另一个解决方案可能是使用boost :: any将所有数据保存在此容器中。

答案 4 :(得分:0)

如果在您的代码上(而不是在外部库中)分配了TypedClass,则可以使用特定的析构函数来防止多次破坏:

template<class T>
struct NullDestructor
{
  void operator()(TypedClass<T> *& t) { /* nothing to do */ }
};

template<class T>
typename TypedClass<T>::Ptr make_fake_shared_ptr( TypedClass<T> * ptr )
{
  return typename TypedClass<T>::Ptr(ptr, NullDestructor<T>() );
}


TypedClass<int>::Ptr int_object = make_fake_shared_ptr<int>(new TypedClass<int>());

TypedClass<float> * ptr = reinterpret_cast<TypedClass<float>*>(int_object.get());
TypedClass<float>::Ptr float_object = make_fake_shared_ptr<float>(ptr);

使用此解决方案,您将负责在最后手动破坏内存:

delete float_object.get();

您可以使用自定义分配器和池来改进此解决方案。