Reputation: 27693
Say I have two classes: Thing
and Holder
:
struct Thing :
std::enable_shared_from_this<Thing>
{
std::shared_ptr<Thing> self()
{
return shared_from_this();
}
};
struct Holder :
std::enable_shared_from_this<Holder>
{
Thing t;
};
int main()
{
auto h = std::make_shared<Holder>();
// will throw std::bad_weak_ptr
h->t.self();
}
I would like Thing
's internal weak_ptr
to use the shared count for Holder
, instead of requiring Holder
to keep a shared_ptr
to Thing
. In the opposite direction, Thing
needs to be able to exist without knowing what a Holder
is (std::make_shared<Thing>().self()
should still work). Is there a decent way to accomplish what I am looking for?
Saying something like std::shared_ptr<Thing> t(h, &h->t);
does not work, since the aliasing constructor for a std::shared_ptr
does not use the enable_shared_from_this
visitor.
With Boost, one could hack around this by overloading sp_enable_shared_from_this
; however, with g++'s implementation, it isn't obvious how to do the equivalent with __enable_shared_from_this_helper
(not to mention we're jumping into "DON'T DO THAT" land).
When in Boost, it isn't terribly difficult to work around this issue by calling _internal_accept_owner
directly:
int main()
{
auto h = boost::make_shared<Holder>();
h->t._internal_accept_owner(&h, &h->t);
h->t.self();
}
With boost::enable_shared_from_this2
, one can embed the needed code in the constructor of Holder
like so:
Holder()
{
boost::shared_ptr<Holder> self = shared_from_this();
t._internal_accept_owner(&self, &t);
}
I'm looking to do the equivalent with std::enable_shared_from_this
.
Upvotes: 3
Views: 1371
Reputation: 35469
If you don't mind it then you can model the composition of a Thing
inside a Holder
via private inheritance rather than with a member object. Then inside a member of Thing
you can 'retrieve' the enclosing Holder
with a static_cast<Holder&>(*this)
downcast -- and after that use shared_from_this
to get access to the shared count.
However, because it is a private base of Holder
, Thing
needs a friend declaration to be able to do the downcast. Since in addition to that the dependency between the two classes is circular , that makes for some heavy coupling.
Upvotes: 1
Reputation: 9569
Ok, now that I understand what you're asking, here's an alternative. You could pass in a shared_ptr< Holder >
to Thing
, allowing it to create it's own aliased shared_ptr. Something like this:
struct Thing : std::enable_shared_from_this<Holder>
{
Thing() {};
Thing( std::shared_ptr< Holder >& holderPtr ) :
m_holder( holderPtr )
{
}
std::shared_ptr< Holder > m_holder;
std::shared_ptr<Thing> self()
{
try
{
return shared_from_this();
}
catch( const std::bad_weak_ptr& )
{
return std::shared_ptr< Thing >( m_holder, this );
}
}
};
struct Holder : std::enable_shared_from_this<Holder>
{
Thing t;
};
Personally seems like it'd be better to just hold a shared_ptr< Thing >
inside Holder
, but this seems like it'd work if you preferred it. Apart from the circular reference between Holder
and Thing
. Guess you could use a weak_ptr< Holder >
inside Thing
instead.
Upvotes: 2