On Thu, 25 Mar 2010 14:58:46 -0500 Jonathon Jongsma <[email protected]> wrote: > On Thu, 2010-03-25 at 18:31 +0100, Murray Cumming wrote: > > On Thu, 2010-03-25 at 14:08 +0000, Chris Vine wrote: > > > Glib::WeakPtr<Gtk::TreeSelection> s = tree_view.get_selection(); > > > ... > > > [some code blocks later] > > > { // scope block for Lock > > > Glib::WeakPtr<Gtk::TreeSelection>::Lock(s); // take a strong > > > reference > > > if (s) s->set_mode(Gtk::SELECTION_SINGLE); > > > } > > > ... > > > > I understand that this might be more correct, but: > > > > a) This doesn't honestly feel very useful in this case. I'm not > > likely to write code that tries to use the TreeSelection after the > > TreeView has been destroyed. Yes, it can happen, but not > > intentionally. So I'm not likely anyway to bother to check the > > pointer before dereferencing it. > > Right. With the above design, people could simply ignore the lock and > use the weak pointer without taking a strong reference. IIRC boost > solves this issue by simply disallowing any use of the pointer via > weak_ptr (they don't provide operator* or operator-> for a weak_ptr). > In other words, you're forced to convert it to a strong reference > before you are able to dereference it. In that case, the developer > is much more likely to be aware that they need to check the result, > e.g.: > > WeakPtr<Gtk::TreeSelection> s = tree_view.get_selection(); > // not allowed to call e.g. s->set_mode() > if ((RefPtr<T> refptr = s.lock())) { > refptr->set_mode(...); > }
You are making two different points. Murray Cumming is saying (I think, he will no doubt correct me if I am wrong) that introducing a weak pointer to glibmm/gtkmm is not worth it to the practical programmer, either because it is not a problem in practice to have a RefPtr holding a live reference to an invalid object, or because no one in practice would check the weak pointer for validity anyway (the second of which is an argument that glib weak pointers are a waste of time and not worth wrapping). You however are happy about introducing weak pointers, and in your example you are happy to check their validity in your if block, but you want to enforce their use in a thread safe way. Your construct is the normal way of achieving thread safety with weak pointers (it was my original proposal should thread safety be wanted: "to make it thread-safe WeakPtr would need to be type convertible to Glib::RefPtr so a strong reference is held in that part of the code, and ... have no Gtk::WeakPtr::operator->() method"). I proposed the separate Lock object as a way of making thread safety optional rather than (as you prefer) mandatory. However, on thinking further about it, I think it will be difficult to achieve thread safety, whether optional or mandatory. Leaving aside the syntax, the steps to be taken on a naive implementation for either would be as follows: 1. Check that the glib weak pointer is not already NULL, so we do not call g_object_ref() on a NULL pointer. 2. If the glib weak pointer is not NULL, call g_object_ref() to take a strong reference and so ensure that the referenced object is kept in existence. 3. Once the continued existence of the referenced object has been secured as mentioned in 2 above, operate on it. The problem with this is that the callback which NULLs the weak pointer is dispatched in the GObject's dispose function. When entering the dispose function, the reference count is already 0 and the object cannot be rescued by calling g_object_ref() (although no memory has been released, as that occurs in the finalize function). The dispose function is analogous to a C++ object's destructor: all its memory is still there but it is doomed. There is therefore a small period of time after the reference count has reached 0 and the dispose function has begun when the weak pointer will not be NULL when tested because, although the dispose function has begun, that part of the dispose function which NULLs the weak pointer has not been reached. The user could still therefore end up operating on an invalid object and trying to dereference a NULL pointer. Instead it will be probably be necessary to have a proxy object shared by all WeakPtrs referencing a particular GObject and tie it into the GObject reference count with g_object_add_toggle_ref() and g_object_remove_toggle_ref(), so that while a WeakPtr is in existence the GObject never enters its dispose function (albeit if all other strong references have been disposed of, the weak pointers report it as dead). This is pretty tedious stuff and for my own part it seems better to me to go back to my even more original proposal and put the weak pointer in Gtk namespace and advertise it as not thread safe. As I conceived it, it is only really intended for referencing GObjects owned by a GTK+ widget, and gtkmm widgets are not thread safe anyway, so we are not going to have a situation where two rival threads are vying for the widget's lifetime. In that case, a simple 'if (s) s->do_it();' is fine, and is as thread safe as the analogous use of g_object_add_weak_pointer() (ie, if two different threads can control widget lifetime, then not thread safe). Chris _______________________________________________ gtkmm-list mailing list [email protected] http://mail.gnome.org/mailman/listinfo/gtkmm-list
