简体   繁体   中英

How can I produce a std::shared_ptr that has locality with it's control block but is an aggregate of another class?

std::make_shared produces, on the heap, an control block/object pair requiring only one allocation and keeping the control block and object in close proximity to help locality.

I'd want to do this, except I want it to be created as an aggregate component of another class. I've looked around, but I don't see such a beast around. Am I missing something?

Eg

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

I want the lifetime to be managed by the encompassing class, but I want weak pointer semantics. Possible?

Neither of those is possible.

The first one, having the lifetime of the shared object managed by some other object, violates the basic purpose of shared_ptr as a class. The point being that, so long as you have a shared_ptr , the thing it points to will always exist . Even with an intrusive pointer, you've violated the intrusive pointer contract if you get an intrusive pointer to it and later destroy it via other means.

The second one doesn't work, because weak pointer semantics are at their core based on the fact that the lifetime of the control block can exceed the lifetime of the object the control block manages. If both objects' lifetimes are managed by some containing object Foo , then when Foo is destroyed, both are destroyed. So the control block's lifetime ends before the weak pointers have all been destroyed.

So no, this doesn't work.

Now yes, there are ways to make such a weak pointer work, but those ways are... unpleasant. It requires having a linked list of all such weak pointer objects, and nulling them out when the control block is destroyed. But thread safety becomes either impossible (imagine copying such a weak pointer while the control block is being destroyed) or requires heavy-weight mutex locking for basic copy operations.

Overall, what you want is simply not what std::shared_ptr is for. What you're looking for is an intrusive pointer. And there's a reason why most intrusive pointer proposals don't have weak semantics.

Aliasing constructor might help:

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> py{foo, &foo.y}; // use control block of foo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM