title unknown method title(:link=>String) (Page context)
Memory management is hard if you use direct pointers to objects.
@ruby|Object@ is already a concurrent reference counted object. Memory related problems to be solved:
# Object should be deleted when parent dies
# Observers should know when the observed object is deleted
# All this between multiple threads
h3. (bad) solution: weak pointer with shared ptr
_see below for a better solution with explicit on_delete notifications_
When an observer wants to trigger an action on the observed object, it calls the "ptr()" method on the weak ptr. The weak ptr returns NULL if the object has been deleted.
In order to use the syntax below, we need a "bool conversion":http://bytes.com/topic/c/answers/62563-overloading-specific-implicit-casts.
// observed object, reference count = 1
Object *foo = new Object();
// --------- MWidget::set_master_object(ObjectHandle &master);
// weak pointer, reference count not changed
// defined in class
ObjectPtr master_;
master_ = master;
// --------- later
// shared pointer, reference count = 2
ObjectHandle master(master_);
if (master) {
master->do_something();
}
h3. implementation of shared_ptr in oscit
# Implement "SharedPtr" (or "Handle" ?) and "WeakPtr" (or "Pointer" ?) templates and use a typedef for ObjectHandle and ObjectPtr.
# no more 'delete' on oscit::Object (let's make Object destructor private) and use 'delete this' in refcount (see "friend delete":http://stackoverflow.com/questions/631783/what-is-the-use-of-having-destructor-as-private).
# No more passing of Object pointers (use handles)
# No more storing of Object pointers (use weak pointers)
# It should be clear that "adopt" does *not* increment reference count.
Special case for "adopt" :
ObjectHandle adopt(Object *obj) {
children_.push_back(ObjectHandle(obj));
obj->release();
return ObjectHandle(obj);
}
Other setters:
void add_observer(ObjectHandle &obj) {
observers_.push_back(ObjectPtr(obj)); // weak pointer
}
Using:
void notify_observers() {
ObjectHandle obj;
// each weak_ptr
if (obj.swap(*it)) {
// changed handle (increased ref count)
obj->notify(xxx);
++it;
} else {
// remove weak_ptr
it = observers_.remove(it);
}
}
h3. (good) solution
Use a Signal/slot mechanism to inform on object delete. And anyone storing a reference should register a callback.
This requires a little more job for the programmer but has *no* performance impact on runtime.
title unknown method title(:link=>String) (Page context)
We should use "boost::make_shared":http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/make_shared.html to avoid smart_ptr overhead during allocation (at least for Value).
title unknown method title(:link=>String) (Page context)
Could we use "boost::signals":http://www.boost.org/doc/libs/1_43_0/doc/html/signals.html to replace the Slot class or part of it ? No, we should not. Signals are slow (because they do many fancy things we do not need) and this part is critical.
h3. we *need* slot support
And not only for connections in Rubyk. We also need them for all kinds of notification purposes.
I even think that if we have a good "slot" class, we can forget about Observer and Observable classes and all boost stuff since the "ObjectHandle" smart pointer is good enough for our needs (and does just what we need).
h3. conclusion
Let's keep and enhance the reference counting classes and smart pointers but replace callbacks with "sigslots":http://sigslot.sourceforge.net/ (no sigslots does not compile, too complicated).
Lets just code a custom class that does just what we need (no templates, just send and receive Value). This means that all callbacks can only speak "Value". But that's something I can live with. As a side effect, it removes the need for virtuals in "emit".
h3. done
liboscit and Mimas have been updated to use Signals exclusively. Works well.
title unknown method title(:link=>String) (Page context)
We could use "intrusive_ptr":http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/intrusive_ptr.html as it is faster then shared_ptr, but is it actually better then "make_shared" ?