我有一个库提供的类,比如:
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);
如果您真的尝试为具有相同大小的数据类型重用相同的对象,而不必从第三方库中分配具有新类型的新对象,则您的选择有限:
- 您不应该从原始指针分配shared_ptr,否则它会被删除两次,导致段错误
- 您可以重用类型(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();
您可以通过使用自定义分配器和池来改进此解决方案。