简体   繁体   中英

Why does enable_shared_from_this lack direct access to the embedded weak_ptr?

I want to use boost signals2 with automatic connection management in a multithreaded application. My class inherits from enable_shared_from_this<> and i want to connect a member method from within another member method. The connection might be rebuilt frequently so my code should be as fast as possible (despite from the boost signals2 performance itself):

typedef boost::signals2::signal<void ()> signal_type;

struct Cat : public enable_shared_from_this<Cat>
{
  void meow ();

  void connect (signal_type& s)
  {
    // can't write this
    s.connect (signal_type::slot_type (&Cat::meow, this, _1).track (weak_from_this ()));

    // ok, but slow?! two temporary smart pointers
    weak_ptr<Cat> const myself (shared_from_this ());
    s.connect (signal_type::slot_type (&Cat::meow, this, _1).track (myself));
  }

  // i am missing something like this in the base class
  // protected:
  //   weak_ptr<Cat> const& weak_from_this ();
};

I know that my design goals might be conflicting (automatic connection management and thread safety but also fast code) but anyway:

  1. Why does enable_shared_from_this<> lack direct access to the embedded weak_ptr<> ? I can't see an opposing reason. Is there no use case similar to mine?

  2. Is there a faster workaround than the one above?

Edit:

I know i can do somethink like this, but i want to avoid the additional storage/init-check penalty:

template <typename T>
struct enable_weak_from_this : public enable_shared_from_this<T>
{
protected:
  weak_ptr<T> /* const& */ weak_from_this ()
  {
    if (mWeakFromThis.expired ())
    {
      mWeakFromThis = this->shared_from_this ();
    }

    return mWeakFromThis;
  }

private:
  weak_ptr<T> mWeakFromThis;
};

The reason you don't have access to the weak_ptr is that enable_shared_from_this doesn't have to use one . Having a weak_ptr is simply one possible implementation of enable_shared_from_this . It is not the only one.

Since enable_shared_from_this is part of the same standard library as shared_ptr , a more efficient implementation could be used than directly storing a weak_ptr . And the committee doesn't want to prevent that optimization.

// ok, but slow?! two temporary smart pointers

That's only one temporary smart pointer. Copy elision/movement should take care of anything but the first object.

It might be because there are no shared_ptr referencing the Cat instance. weak_ptr requires there to be at least one active shared_ptr .

Try placing a shared_ptr as member variable and assign to it first in the connect method:

typedef boost::signals2::signal<void ()> signal_type;

struct Cat : public enable_shared_from_this<Cat>
{
  void meow ();
  boost::shared_ptr<Cat> test;

  void connect (signal_type& s)
  {
    test = shared_from_this();
    s.connect (signal_type::slot_type (&Cat::meow, this, _1).track (weak_from_this ()));
  }
};

But basically, there can be no weak_ptr if there are no shared_ptr . And if all shared_ptr disapear while the weak_ptr is still in use, then the weak_ptr could point to an non-existant object.

Note: My test should not be used in production code as it will cause the object to never be deallocated.

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