2

我有一个像这样的库提供的类:

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

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

欢迎提出建议。

4

5 回答 5

5

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 >= 1.53.0,那么还有boost::reinterpret_pointer_cast. 所以你可以写:

TypedClass<float>::Ptr float_object = boost::reinterpret_pointer_cast<TypedClass<float> >(int_object);
于 2013-09-05T02:40:21.000 回答
1

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

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

作为您的示例,我建议如下代码:

float* float_ptr = reinterpret_cast<float*>(&int_object->m_data);
// Do something with *float_ptr
// And never delete it!
于 2013-09-03T08:21:35.000 回答
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));
于 2013-09-04T08:34:24.230 回答
0

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

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

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

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

于 2013-09-02T19:25:02.957 回答
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();

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

于 2013-09-04T22:26:52.387 回答