Boost logo

Boost Users :

Subject: [Boost-users] Boost.Signals2 - if slot (functor of lambda) destructs the signal, calling the slot itself -> safe for functor?
From: nice sw123 (nicesw123_at_[hidden])
Date: 2015-09-04 17:42:29


Hi there,

If I connect a signal to a slot (functor or lambda), and the signal is
then run, it calls the slot.
What if the slot now has code that causes the signal to destruct?

Will this "self-destruct" the slot (functor or lambda), by calling
it's destructor BEFORE the slot-call has finished executing??? This
would be a disaster!

But it seems like is is safe.
It seems:
Even if the signal is destructed (from it's own slot-call), the slot
destructor does not yet get called, until the slot-call has finished.
Which would be safe.
(Code example below)

But is this really the case? Is this always safe? (If so: how does
this roughly work?)

Thanks.

/////////////////////////////////////////////////////////////////////
#include <iostream>
#include <string>
#include <boost/signals2.hpp>
#include <functional>
#include <map>

using namespace std;

using FuncSig = void();

class BaseWrapper {
public:
  BaseWrapper() { cout << "BaseWrapper() " << ++mm[""] << endl; }
  BaseWrapper(const string &n) : name{n} { cout << "BaseWrapper() "
<< name << ' ' << ++mm[name] << endl; }
  BaseWrapper(const BaseWrapper &other) : name{other.name} { cout <<
"BaseWrapper(const BaseWrapper &other) " << name << ' ' << ++mm[name]
<< endl; }
  virtual ~BaseWrapper() { cout << "~BaseWrapper() " << name << ' ' <<
mm[name]-- << endl; }
private:
  static map<const string, int> mm; // static counter
  const string name;
};

map<const string, int> BaseWrapper::mm;

class MySig : BaseWrapper, public boost::signals2::signal<FuncSig> {
};

using Sig = MySig; //boost::signals2::signal<FuncSig>;

class A {
public:
  A() {}

  boost::signals2::connection add_listener(const string &str, const
Sig::slot_type &slot) {
    //my_map.emplace(str, Sig{});
    auto x = my_map.emplace(std::piecewise_construct,
                            std::forward_as_tuple(str),
                            std::forward_as_tuple());
    return x.first->second.connect(slot);
  }

  void remove_listener(const string &str) {
    auto it = my_map.find(str);
    if (it != my_map.cend()) {
      my_map.erase(it);
    }
  }

  void call(const string &str) {
    auto it = my_map.find(str);
    if (it != my_map.cend()) {
      it->second();
    }
  }
private:
  map<const string, Sig> my_map;
};

class Functor : BaseWrapper {
public:
  Functor(A *a_, int x_) : BaseWrapper{"Functor"}, a{a_}, x{x_} {}
  void operator()() const {
    cout << " this == " << this << endl;
    cout << " x == " << x << endl;
    a->remove_listener("hello");
    cout << " this == " << this << endl;
    cout << " x == " << x << endl;
  }
private:
  A *a;
  int x;
};

int main()
{
  A a;
  {
    Functor fun{&a, 4};
    a.add_listener("hello", fun);
  }
  a.call("hello");
  std::cout << "end" << endl;
  return 0;
}
/////////////////////////////////////////////////////////////////////


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net