shared_array元素作为shared_ptr

Element of shared_array as shared_ptr?

本文关键字:shared ptr 元素 array      更新时间:2023-10-16

如果我有一个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> ,并且始终使用 boost 而不是 std(即使对于非数组(。我希望这会起作用,但我还没有机会尝试它:

shared_ptr<int[]> array(new int[10]);
shared_ptr<int> element(array, &array[2]);

当然,我仍然更喜欢实例方法语法,但我想我对那个语法不走运(没有修改 Boost(:

shared_ptr<int> element = array.shared_ptr_to(2);

其他人有什么想法吗?

你在做奇怪的事情。为什么需要shared_ptr元素?您是否希望将数组元素传递到其他地方并按住数组以防止删除?

如果是,那么std::vector<shared_ptr<T>>更适合这样做。该解决方案是安全的、标准的,并且在移除对象时具有精细的粒度

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

在这里,sp1sp2共享foo对象的所有权,但sp2指向它的成员。如果sp1被销毁,foo对象仍将处于活动状态,并且sp2仍然有效。

这是我最后所做的。

我自己实现了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的内容,并且(我们期望(不太擅长分析boost事物或自定义事物的内容。

所以我认为我所做的基本上是最佳的。 :)