如何生成一个 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 的值