Boost :: signals2 - create an object with a 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(); } 

Conclusion: "The slot is called!" and no accident or anything else. This is why I have a few questions:

1) Why is there no glitch?

2) Why is there no failure even if the slot function assigns something to an object that does not exist?

3) How can I get a signal to automatically track the life of its slots? I mean, when the slot is destroyed, it turns off.

Question number 3 is the most important, because I need to implement the observer pattern, and very often the lifetime of the observers (slots) will not be static (all the time the application is running).

+2
source share
3 answers

1) You are lucky. If not, you will get a segmentation error.

2) The memory has not been overwritten.

3) You can use slot :: track to automatically disconnect when deleting a tracked object. Boost.Signals2 could track objects that are driven 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 for tracking 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; } 
+3
source

1 and 2) Actually this behavior is undefined. You used the dereference operator, now the connection has the value object_with_slot, its address can be assigned by the memory manager for any other process. Coincidentally, this is still a "valid address". And ptr can be assigned to any other value without memory leak.

Try something like this and you will see that it explodes every time

 #include <boost/signals2.hpp> #include <iostream> struct object_with_slot { object_with_slot() { member = new int(10); } ~object_with_slot() { delete member; //comment this line and everything works again } void operator()() { std::cout << "Slot called!" << std::endl; *member = 50500; //it was destroyed above } int *member; }; int main() { boost::signals2::signal<void ()> sig; object_with_slot * ptr = new object_with_slot; sig.connect(*ptr); delete ptr; ptr = 0x0; sig(); } 

3) You can put another signal in the destructor of the object_with_slot object, after which it can notify when it is called.

+1
source

Very dangerous examples are given. Take a look:

 #include <iostream> #include <memory> #include <boost/signals2.hpp> struct object_with_slot { object_with_slot() { std::cout << "ctor\n"; } object_with_slot(const object_with_slot &) { std::cout << "cctor\n"; } ~object_with_slot() { std::cout << "dtor\n"; } 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; } 

What do you think this code does (g ++ 4.8.1, libboost 1.54)?

 ctor cctor cctor cctor cctor cctor cctor cctor cctor dtor dtor dtor dtor dtor cctor dtor cctor dtor dtor dtor cctor dtor Slot called! dtor dtor 

I do not think this behavior was expected. Since we are passing a copy (by value) *ptr (an instance of object_with_slot ) to the connect method. This can be solved, for example, with reference wrappers:

 sig.connect(sig_type::slot_type(boost::ref(*ptr)).track_foreign(ptr)); // ptr is tracked 

Be careful with patterns and types.

0
source

All Articles