如何生成一个 std::shared_ptr 与其控制块具有局部性但又是另一个类的集合?

Posted

技术标签:

【中文标题】如何生成一个 std::shared_ptr 与其控制块具有局部性但又是另一个类的集合?【英文标题】:How can I produce a std::shared_ptr that has locality with it's control block but is an aggregate of another class? 【发布时间】:2019-06-18 18:09:38 【问题描述】:

std::make_shared 在堆上生成一个控制块/对象对,只需要一次分配并保持控制块和对象靠近以帮助定位。

我想这样做,但我希望它被创建为另一个类的聚合组件。我环顾四周,但我没有看到这样的野兽。我错过了什么吗?

例如

struct Bar ;
struct Foo

  // This would allocate the control block and object Bar on
  // the heap, which is pointed at by Foo.
  std::shared_ptr<Bar> x;

  // Example that would allocate the control block and object Bar as
  // an aggregate part of Foo. local_shared_ptr is not an actual thing
  // in the stl that I can find.
  std::local_shared_ptr<Bar> y;

【问题讨论】:

如果不独立管理对象的内存位置的生命周期,您就不能拥有共享所有权。共享所有权意味着该对象将在其最后一个所有者释放它时被销毁,无论碰巧是哪个所有者。在这里,y 的生命周期永远不会超过 Foo 的生命周期,因此 Foo 拥有它的唯一所有权。编辑:我知道您希望Bar 存在于Foo 的存储中,而不是驻留在免费存储中。也许我误解了这个问题。 @Jarod42,大概就像您将 std::shared_ptr 分配给使用 std::make_shared 的一对时所做的那样,重定向控制块指针。 @FrançoisAndrieux,当然可以。如果对象被删除,那么我们会像处理std::optional 一样做一些事情,只是如果对象没有被控制块指向,就不要调用析构函数。 我担心如果保存Bar 的存储空间的Foo 被销毁,则必须立即释放该存储空间,因此您别无选择,只能销毁Bar。从这个意义上说,所有权不是共享的。 Foo 需要有权销毁 Bar,即使其他所有者仍然需要它。 @FrançoisAndrieux,嗯,好点子。我希望由包含类管理生命周期,但我想要弱指针语义。可能吗? 【参考方案1】:

我希望生命周期由包含类管理,但我希望弱指针语义。可能吗?

这些都不可能。

第一个,具有由其他对象管理的共享对象的生命周期,违反了shared_ptr作为一个类的基本目的。关键是,只要你有一个shared_ptr,它所指向的东西就会永远存在。即使使用了一个侵入式指针,如果你得到一个指向它的侵入式指针然后通过其他方式销毁它,你就违反了侵入式指针协定。

第二个不起作用,因为弱指针语义的核心是基于 控制块 的生命周期可以超过控制块管理的对象的生命周期这一事实。如果两个对象的生命周期都由一些包含对象Foo 管理,那么当Foo 被销毁时,两者都被销毁。所以控制块的生命周期在弱指针全部被销毁之前就结束了。

所以不,这不起作用。

现在是的,有一些方法可以使这样的弱指针工作,但这些方法......令人不快。它需要拥有所有此类弱指针对象的链表,并在控制块被销毁时将它们清空。但是线程安全要么变得不可能(想象在控制块被销毁时复制这样一个弱指针),要么需要对基本复制操作进行重量级互斥锁。

总的来说,你想要的根本不是std::shared_ptr 的用途。您正在寻找的是一个侵入式指针。大多数侵入性指针建议没有弱语义是有原因的。

【讨论】:

【参考方案2】:

别名构造函数可能会有所帮助:

struct Bar ;
struct Foo

    std::shared_ptr<Bar> x;
    Bar y;
;

auto foo = std::make_shared<Foo>();
foo->x = std::make_shared<Bar>();
std::shared_ptr<Bar> pyfoo, &foo.y; // use control block of foo

【讨论】:

但这意味着有两个 Bar 对象,并且您仍然在堆上分配了控制块。

以上是关于如何生成一个 std::shared_ptr 与其控制块具有局部性但又是另一个类的集合?的主要内容,如果未能解决你的问题,请参考以下文章

智能指针std::shared_ptr初始化时可能泄露的地方

C++:如何初始化以下 std::shared_ptr 构造函数数组

SWIG:如何从 SwigPyobject 获取包装的 std::shared_ptr 的值

如何正确复制给定 shared_ptr 的对象

std::list<std::shared_ptr>::erase 得到一个 SIGSEGV

这是 std::vector 和 std::shared_ptr 内存泄漏的错误吗?