如果我有boost::shared_array<T>
(或boost::shared_ptr<T[]>
),有没有办法获得与数组共享的boost::shared_ptr<T>
?
例如,我可能想写:
shared_array<int> array(new int[10]);
shared_ptr<int> element = &array[2];
我知道我无法使用&array[2]
,因为它只有int *
类型,shared_ptr<int>
拥有一个隐式构造函数来获取该类型会很危险。理想情况下shared_array<int>
会有一个实例方法,例如:
shared_ptr<int> element = array.shared_ptr_to(2);
不幸的是我找不到这样的东西。 shared_ptr<int>
上有一个别名构造函数,它将与另一个shared_ptr<T>
别名,但不允许使用shared_array<T>
别名;所以我也写不出来(它不会编译):
shared_ptr<int> element(array, &array[2]);
//Can't convert 'array' from shared_array<int> to shared_ptr<int>
我使用的另一个选项是使用std::shared_ptr<T>
(std
代替boost
)。 T[]
的专业化不是标准化的,所以我想自己定义一下。不幸的是,我认为实际上不可能以不破坏别名构造函数内部的方式,因为它试图将我的std::shared_ptr<T[]>
强制转换为它自己的特定于实现的超类型,这是不可能的。 (我目前只是从增强版继承而来。)这个想法的好处在于我可以实现我的实例shared_ptr_to
方法。
这是我尝试过的另一个想法,但我认为它不足以被接受为我们可能在整个大型项目中使用的东西。
template<typename T>
boost::shared_ptr<T> GetElementPtr(const boost::shared_array<T> &array, size_t index) {
//This deleter works by holding on to the underlying array until the deleter itself is deleted.
struct {
boost::shared_array<T> array;
void operator()(T *) {} //No action required here.
} deleter = { array };
return shared_ptr<T>(&array[index], deleter);
}
接下来我要尝试升级到Boost 1.53.0(我们目前只有1.50.0),使用shared_ptr<T[]>
代替shared_array<T>
,并且始终使用{{1而不是boost
(即使对于非数组)。我希望这会有效,但我还没有机会尝试它:
std
当然我还是更喜欢实例方法语法,但我想我对那个没有好处(没有修改Boost):
shared_ptr<int[]> array(new int[10]);
shared_ptr<int> element(array, &array[2]);
其他人有什么想法吗?
答案 0 :(得分:1)
你做的很奇怪。
为什么你需要shared_ptr
元素?您是否希望将数组元素传递到其他位置并从删除中按住数组?
如果是,那么std::vector<shared_ptr<T>>
更适合于此。该解决方案是安全的,标准的,并且在删除对象时具有精细的粒度
答案 1 :(得分:0)
boost::shared_ptr
似乎并不支持这种做法。也许你可以使用自定义删除器来解决这个问题。但是std::shared_ptr
提供了一个特殊的构造函数来支持你想要的东西:
struct foo
{
int a;
double b;
};
int main()
{
auto sp1 = std::make_shared<foo>();
std::shared_ptr<int> sp2 (sp1,&sp1->a);
}
此处,sp1
和sp2
共享foo
对象的所有权,但sp2
指向其成员。如果sp1
被销毁,则foo
对象仍然有效且sp2
仍然有效。
答案 2 :(得分:0)
这是我最后所做的。
我自己实现了shared_array<T>
。它有效地扩展了shared_ptr<vector<T>>
,除了它实际上扩展了我自己的vector<T>
包装器,以便用户无法获取向量。这意味着我可以保证不会调整大小。然后我实现了我需要的实例方法 - 包括weak_ptr_to(size_t)
,当然还有operator[]
。
我的实现使用std::make_shared
来生成向量。因此,向量与控制块分开分配其内部数组存储,但向量本身成为控制块的成员。因此,它等同于忘记将std::make_shared
用于普通类型 - 但由于这些是数组,因此它们可能很大而且很少,所以它不那么重要。
我还可以创建一个基于shared_ptr<T>
但带有default_delete<T[]>
或者需要的实现的实现,但它必须从控制块中单独分配数组(因此与向量相比没有太多保存) )。我不认为有一种可移植的方法可以在控制块中嵌入动态大小的数组。
或者我的实现可以基于boost::shared_array<T>
,并在获取元素指针时使用自定义删除器(根据问题中的示例)。在大多数情况下,这可能更糟糕,因为我们不是一次性命中分配数组,而是每次使用别名指针时都会遇到命中(对于非常短暂的指针,可能会发生很多事情)。
我认为让它更优化的唯一合理方法是使用最新的提升(如果它有效;在我改变主意之前我没有尝试过,主要是因为我对我的渴望自己的实例成员)。当然,这意味着在任何地方都使用boost
个,即使对于单个对象也是如此。
但是,我使用的主要优点是Visual Studio的调试器(我被告知)擅长显示std :: shared_ptrs和std :: vectors的内容,并且(我们期待不太善于分析促进事物或习惯事物的内容。
所以我认为我所做的基本上是最优的。 :)