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

Casting between two type-templated classes using shared pointers

本文关键字:之间 转换 类型 指针 共享 两个      更新时间:2023-10-16

我有一个库提供的类,比如:

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继承的问题,但这在这里是不可能的。

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

欢迎提出建议。

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

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

基本上,这构造了一个shared_ptr,它从r获取deleter和refcounting,除了它保存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>=1.53.0,那么还有boost::reinterpret_pointer_cast。所以你可以写:

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

如果您真的尝试为具有相同大小的数据类型重用相同的对象,而不必从第三方库中分配具有新类型的新对象,则您的选择有限:

  1. 您不应该从原始指针分配shared_ptr,否则它会被删除两次,导致段错误
  2. 您可以重用类型(shared_ptr),以便可以通过运算符=()直接"复制";或者cat原始指针,并确保您没有进行影响内存分配/删除的更改

举个例子,我建议代码如下:

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

您可以使用boost指针强制转换。这是一个非常丑陋的解决方案,但至少裁判计数会以这种方式工作。

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));

我认为你不能,除非你用两个参数typename重载共享ptr类本身,因为它保留对数据的引用,并在计数为0时删除。但当你必须从一种类型转到另一种类型时,boost共享ptr会认为你无论如何都发布了数据。

shared_ptr p=ptr//如果ptr和p的类型相同,则添加一个ref。

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

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

如果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();

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