Search code examples
c++boostsignalsboost-signalsboost-signals2

Boost::signals2 - descruction of an object with the slot


Consider this:

#include <boost/signals2.hpp>
#include <iostream>

struct object_with_slot
{
void operator()()
{
   std::cout << "Slot called!" << std::endl;
   member = 50500;
}
int member;
};


int main()
{
boost::signals2::signal<void ()> sig;

object_with_slot * ptr = new object_with_slot;
sig.connect(*ptr);

delete ptr;

sig();
}

Output is "Slot called!" and no crash or anything. That's why I have a few questions:

1) Why there is no crash?

2) Why there is no crash even if the slot function assigns something to object which doesn't exist?

3) How can I make the signal automatically track the lifetime of its slots? I mean when the slot is destroyed, it gets disconnected.

The question number 3 is the most important, as I need to implement observer pattern and very often lifetime of observers (slots) won't be static (for the whole time when app is running).


Solution

  • 1) You're lucky. If not, you'll get a segmentation fault.

    2) The memory was not overwritten in any way.

    3) You could use slot::track to automatically disconnect when the tracked object gets deleted. Boost.Signals2 could track objects that are managed by boost::shared_ptr.

    #include <boost/signals2.hpp>
    #include <boost/shared_ptr.hpp>
    
    struct object_with_slot
    {
        void operator()()
        {
           std::cout << "Slot called!" << std::endl;
           member = 50500;
        }
        int member;
    };
    
    //
    int main()
    {
        typedef boost::signals2::signal<void ()> sig_type;
        sig_type sig;
    
        {
            boost::shared_ptr<object_with_slot> ptr(new object_with_slot);
            sig.connect(sig_type::slot_type(*ptr).track(ptr));
    
            // 'object_with_slot' managed by ptr is destroyed
        }
    
        sig(); // 'object_with_slot' not called here.
    
        return 0;
    }
    

    UPDATE:
    Added code to track objects for std::shared_ptr and std::weak_ptr:

    #include <memory>
    #include <boost/signals2.hpp>
    
    // added specializations for std::weak_ptr and std::shared_ptr
    namespace boost
    {
      namespace signals2
      {
        template<typename T> struct weak_ptr_traits<std::weak_ptr<T> >
        {
          typedef std::shared_ptr<T> shared_type;
        };
    
        template<typename T> struct shared_ptr_traits<std::shared_ptr<T> >
        {
          typedef std::weak_ptr<T> weak_type;
        };
      }
    }
    
    struct object_with_slot
    {
        void operator()()
        {
           std::cout << "Slot called!" << std::endl;
           member = 50500;
        }
        int member;
    };
    
    //
    int main()
    {
        typedef boost::signals2::signal<void ()> sig_type;
        sig_type sig;
    
        std::shared_ptr<object_with_slot> ptr(new object_with_slot);
        sig.connect(sig_type::slot_type(*ptr).track_foreign(ptr)); // ptr is tracked
    
        sig();
    
        return 0;
    }