8

如果我有一个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],因为它只有 type ,并且拥有一个采用该类型的隐式构造函数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[]没有标准化,所以我想自己定义。不幸的是,我认为这实际上是不可能的,它不会破坏别名构造函数的内部结构,因为它试图将 mystd::shared_ptr<T[]>转换为它自己的特定于实现的超类型,这不再可能。(我的目前只是从 boost 继承。)这个想法的好处是我可以实现我的实例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);

其他人有什么想法吗?

4

3 回答 3

1

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

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

于 2013-03-21T14:06:06.833 回答
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 的内容,并且(我们期望)不太擅长分析 boost 的内容东西或定制的东西。

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

于 2013-03-21T23:16:19.517 回答
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);
}

在这里,sp1sp2共享对象的所有权foo只是sp2指向它的一个成员。如果sp1被销毁,该foo对象将仍然活着并且sp2仍然有效。

于 2013-03-21T14:23:35.200 回答