Jump to content
  • Advertisement
Sign in to follow this  
Sol Blue

This fixed a shared_from_this() problem. Why?

This topic is 3902 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, After struggling with a problem with enable_shared_from_this, I fixed it, but I have no idea why my solution works, which bugs me. I wanted my class (say Test) to inherit from enable_shared_from_this, but it also inherited from another class (Subsystem) which *also* had shared_from_this().
class Test : public Subsystem, public enable_shared_from_this<Test>
{
public:
	using enable_shared_from_this<Test>::shared_from_this;
};
class Subsystem : public enable_shared_from_this<Subsystem>
{
};
But when I had that, this code threw a bad_weak_ptr exception:
shared_ptr<Test> t1;
t1.reset(new Test());
shared_ptr<Test> t2;
t2 = t1->shared_from_this();   // exception!
Now, at first I figured this was an ambiguity problem -- it didn't know whether to use Test's shared_from_this() or the copy its base class, Subsystem, also had. But isn't having this line
using enable_shared_from_this<Test>::shared_from_this;
supposed to fix that? Anyway, I ended up switching the order Test inherited from the classes, which worked fine.
// No problem if Subsystem comes second.
class Test : public enable_shared_from_this<Test>, public Subsystem
{
public:
	using enable_shared_from_this<Test>::shared_from_this;
};
Can anyone explain why the order matters?

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by Sol Blue
I wanted my class (say Test) to inherit from enable_shared_from_this, but it also inherited from another class (Subsystem) which *also* had shared_from_this
Eeek, a variation on the dreaded diamond inheritance - Run for the hills!

It sounds like a job for virtual inherritance. Good luck with that one!!!
*runs away to hide*

Share this post


Link to post
Share on other sites
Quote:
Original post by iMalc
Quote:
Original post by Sol Blue
I wanted my class (say Test) to inherit from enable_shared_from_this, but it also inherited from another class (Subsystem) which *also* had shared_from_this
Eeek, a variation on the dreaded diamond inheritance - Run for the hills!


Given the nature of C++ templates, it's more of a dreaded fools gold inheritance kind of thing, what with each enable_shared_from_this being a distinctly separate leaf node.

I'm not entirely sure how applicable this is to your class heiarchy, but CRTP is commonly used in such situations (and in fact, you're already kind of using it with enable_shared_from_this, given that it relies on this pattern itself).

The natural extension is to just apply CRTP to the entire class heiarchy:

template < typename Self > class System : public enable_shared_from_this< Self > { ... };
class Test : public System< Self > { ... };



Quote:
Can anyone explain why the order matters?


Actually, you've just hidden the problem:
shared_ptr<Subsystem> t3 = t1->Subsystem::shared_from_this(); // exception with your current code!



The problem is that enable_shared_from_this isn't meant to be inherited multiple times, and each one acts completely independant from each other, leading only one to be properly initialized -- whichever is constructed first, apparently, hence the differing results when you changed the inheritance order. The bad_weak_ptr exceptions result from this.

Instead, write your own coercion of shared_from_this.

// Base class as usual
class Subsystem : public enable_shared_from_this<Subsystem>
{
// Note: Member functions would have used Subsystem::shared_from_this like
// my t3 line does, hence why your "solution" of inheritence reordering
// only masks the problem, instead of solving it.
};

class Test : public Subsystem
{
public:
shared_ptr<Test> shared_from_this() { return static_pointer_cast<Test>(Subsystem::shared_from_this()); }
shared_ptr<Test> shared_from_this() const { return static_pointer_cast<Test>(Subsystem::shared_from_this()); }
};

Share this post


Link to post
Share on other sites
MaulingMonkey, thanks a lot! That seems to have worked. It's a much cleaner, more satisfying solution, too. I never liked having the two shared_from_this()'s. Thanks for pointing me to the pattern.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!