After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 788646 - Mixing C & C++: Clarify ownership of wrap() result
Mixing C & C++: Clarify ownership of wrap() result
Status: RESOLVED FIXED
Product: gtkmm
Classification: Bindings
Component: reference documentation
unspecified
Other All
: Normal normal
: ---
Assigned To: gtkmm-forge
gtkmm-forge
Depends on:
Blocks:
 
 
Reported: 2017-10-07 18:12 UTC by Daniel Boles
Modified: 2017-11-15 14:47 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Mixing C & C++: Clarify ownership of wrap() result (2.86 KB, patch)
2017-10-07 18:12 UTC, Daniel Boles
committed Details | Review

Description Daniel Boles 2017-10-07 18:12:06 UTC
Maybe no one else found this as vague as I did, but I think it’d be much better
to be clear how wrap() works and what users should (not) do about lifetime, etc.
Comment 1 Daniel Boles 2017-10-07 18:12:10 UTC
Created attachment 361103 [details] [review]
Mixing C & C++: Clarify ownership of wrap() result

Make it clear that wrap() returns a pointer to an instance owned by
glibmm, so users should not try to delete it. Also mention the effect on
refcount, i.e. nothing if (!take_copy). Finally, show the C++ instance
actually being used (though a better example would show more advantage).

While here, I split the long paragraphs for readability & to help git, &
add some missing <classname>/<function> tags for readability/semantics.
Comment 2 Kjell Ahlstedt 2017-10-11 08:55:32 UTC
The ownership of the C++ wrapper is more complicated than you describe. Perhaps
that's why it's not fully described in the tutorial.

Perhaps it's better to say that the C++ instance is bound to the C instance.
This is done with a GQuark in the C instance which contains the address of the
C++ instance. And Glib::ObjectBase contains GObject* gobject_.
When the C instance is finalized, the C++ wrapper instance is informed by a call
to Glib::ObjectBase::destroy_notify_callback_().

Who shall delete the C++ wrapper? There are 3 cases.

1. The C++ class does not inherit from Gtk::Object. Its pointer is stored in
   a Glib::RefPtr.

   The C++ instance is deleted when the C instance loses its last reference.
   See Glib::ObjectBase::destroy_notify_().

2. The C++ class inherits from Gtk::Object. It's not "managed".
   Typically this is a C++ instance which is a member of another C++ instance,
   such as a Gtk::Button which is a member of a class derived from Gtk::Box.

   The creator of the C++ instance is responsible for deleting it. But don't
   delete it before you want the C instance to die. Gtk::Object's destructor
   calls g_object_run_dispose(c_instance).

3. The C++ class inherits from Gtk::Object. It's "managed". Usually this means
   that Gtk::manage(cxx_instance) has been called.

   The C++ instance is deleted when the C instance loses its last reference.
   See Gtk::Object::destroy_notify_().

Consider a wrap() function that corresponds to a C++ class that inherits from
Gtk::Object. When it creates a new C++ wrapper instance,
Gtk::Object::Object(GObject* castitem) is called. Gtk::Object::_init_unmanage()
then decides if the new C++ instance is managed or not managed based on the
result of a call to g_object_is_floating(c_instance).
Floating ref == not managed; no floating ref == managed.

All this is too much for the gtkmm tutorial. I hope it can be explained in a
reasonably short form without being misleading.
Comment 3 Daniel Boles 2017-10-11 10:27:47 UTC
Thanks for the details! So, the ownership of the C instance dictates whether the user should free the result of wrap(), and they should only delete the wrapper if the C instance was floating at the time they wrap()ped it? If I understood it correctly, that seems like a succinct enough summary - which is why I suspect I didn't :)
Comment 4 Kjell Ahlstedt 2017-10-11 15:27:38 UTC
Let me try a slightly less succinct summary:

The wrapper shall be explicitly deleted if
  - it's a widget or other class that inherits from Gtk::Object, and
  - the C instance is floating when the wrapper is created, and
  - Gtk::manage() is not called.
(Don't delete the wrapper before you want the C instance to die.)

In all other cases the wrapper is automatically deleted when the last reference
of the C instance is dropped.
Comment 5 Kjell Ahlstedt 2017-11-15 14:47:25 UTC
Daniel, I have pushed your patch, followed by a patch based on comment 4,
to the master branch and the gtkmm-3-22 branch of gtkmm-documentation.