首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >作为shared_ptr的shared_array元素?

作为shared_ptr的shared_array元素?
EN

Stack Overflow用户
提问于 2013-03-21 21:50:26
回答 3查看 2.6K关注 0票数 8

如果我有一个boost::shared_array<T> (或boost::shared_ptr<T[]>),有没有办法获得与阵列共享的boost::shared_ptr<T>

例如,我可能想要这样写:

代码语言:javascript
复制
shared_array<int> array(new int[10]);
shared_ptr<int> element = &array[2];

我知道我不能使用&array[2],因为它只有int *类型,而且对于shared_ptr<int>来说,拥有一个接受该类型的隐式构造函数是很危险的。理想情况下,shared_array<int>上应该有一个实例方法,类似于:

代码语言:javascript
复制
shared_ptr<int> element = array.shared_ptr_to(2);

不幸的是,我找不到这样的东西。在shared_ptr<int>上有一个别名构造函数,它将与另一个shared_ptr<T>进行别名,但它不允许与shared_array<T>进行别名;所以我也不能写这个(它不会编译):

代码语言:javascript
复制
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[]>转换为它自己的特定于实现的超类型,而这已经不可能了。(我的目前只是从boost中继承过来的。)这个想法的好处是我可以实现我的实例shared_ptr_to方法。

这是我尝试过的另一个想法,但我不认为它的效率足够高,不足以让我们在整个大型项目中使用它。

代码语言:javascript
复制
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 (即使是非数组)。我希望这能起作用,但我还没有机会尝试一下:

代码语言:javascript
复制
shared_ptr<int[]> array(new int[10]);
shared_ptr<int> element(array, &array[2]);

当然,我仍然更喜欢实例方法语法,但我想我在这方面不太走运(除了修改Boost):

代码语言:javascript
复制
shared_ptr<int> element = array.shared_ptr_to(2);

其他人有什么想法吗?

EN

回答 3

Stack Overflow用户

发布于 2013-03-21 22:06:07

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

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

票数 1
EN

Stack Overflow用户

发布于 2013-03-21 22:23:35

boost::shared_ptr本身似乎并不支持这一点。也许你可以用一个自定义的deleter来解决这个问题。但是std::shared_ptr提供了一个特殊的构造函数来支持您想要的内容:

代码语言:javascript
复制
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仍然有效。

票数 0
EN

Stack Overflow用户

发布于 2013-03-22 07:16:20

这是我最后做的事情。

我制作了自己的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 (如果它有效;在我改变主意之前,我没有尝试到这一步,主要是因为我希望自己的实例成员)。当然,这意味着在任何地方都要使用boost,即使是单个对象。

但是,我使用Visual Studio的调试器的主要优点是(我被告知)擅长显示std::shared_ptrs和std::vectors的内容,而(我们期望的)不太擅长分析boost内容或自定义内容。

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15549413

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档