How to use wrap() to get temporary C++ views of longer-lived C instances

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

How to use wrap() to get temporary C++ views of longer-lived C instances

Daniel Boles
If I have an existing C widget and just want to use C++ syntax with it for a while, what exactly do I do? Well, OK - obviously, I call Gtk::Whatever::Wrap(c_instance) and get a pointer to a C++ class from that.

But what are the ownership semantics of that pointer? I'm responsible for deleting it, right?

If so, then why do some parts of the gtkmm implementation call wrap(), do something with the pointer, then discard it, without ever deleting or unreffing? Is that leaking references to the C instance, or what did I miss?

e.g.:
 * https://git.gnome.org/browse/gtkmm/tree/gtk/src/menushell.ccg?h=gtkmm-3-22#n73
 * https://git.gnome.org/browse/gtkmm/tree/gtk/src/printjob.ccg?h=gtkmm-3-22#n20


Basically, my widget already exists in C and must continue to exist there. I just want to return a wrapped C++ instance from a helper method and use it in a few places, so I zget nicer/consistent syntax.

My gut feeling was to call wrap(c_instance, true) so that I just take a ref instead of ownership, then have my method return a unique_ptr<>, which would result in the C++ instance being deleted and (because I called wrap() with take_copy = true) unreffed from my side.

But this seems somehow to result in my C instance going away, lots of criticals, then a segfault, etc. So, presumably the unique_ptr isn't right.


So, *can* I just use gtkmm temporarily like this? How do I do it? Can we improve the documentation so that  lifetime and deletion of the returned wrapper are clear? And might we need to fix some parts of gtkmm itself?

Thanks!


_______________________________________________
gtkmm-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtkmm-list
Reply | Threaded
Open this post in threaded view
|

Re: How to use wrap() to get temporary C++ views of longer-lived C instances

Daniel Boles
On 7 October 2017 at 17:56, Daniel Boles <[hidden email]> wrote:
Is that leaking references to the C instance, or what did I miss?

And the whole C++ instance itself, it would seem.

After really thinking about this, I feel like I must've missed something obvious, and glibmm must keep a lazily initialised dictionary of wrapped widgets to free later, or something. :) But I suspect tracking down the relevant code is still beyond my current level of skill.

I guess for now I'll do what gtkmm does: just use the pointer and don't mess with its lifetime, and hopefully find out what that's OK later!




_______________________________________________
gtkmm-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtkmm-list
Reply | Threaded
Open this post in threaded view
|

Re: How to use wrap() to get temporary C++ views of longer-lived C instances

Daniel Boles
D'oh...

On 7 October 2017 at 18:07, Daniel Boles <[hidden email]> wrote:
After really thinking about this, I feel like I must've missed something obvious, and glibmm must keep a lazily initialised dictionary of wrapped widgets to free later, or something. :) But I suspect tracking down the relevant code is still beyond my current level of skill.

The bad news is that I didn't find this sooner. The good news is that I wasn't too dense to track it down! So, for posterity, here's what the derived wrap() functions ultimately call:


// This is a factory function that converts any type to
// its C++ wrapper instance by looking up a wrap_new() function in a map.
//
ObjectBase*
wrap_auto(GObject* object, bool take_copy)
{
  if (!object)
    return nullptr;

  // Look up current C++ wrapper instance:
  ObjectBase* pCppObject = ObjectBase::_get_current_wrapper(object);

  if (!pCppObject)
  {
    // There's not already a wrapper: generate a new C++ instance.
    pCppObject = wrap_create_new_wrapper(object);

    // [...]
  }

  // take_copy=true is used where the GTK+ function doesn't do
  // an extra ref for us, and always for plain struct members.
  if (take_copy)
    pCppObject->reference();

  return pCppObject;
}


So, glibmm owns the returned wrapper, and we users don't need to - and can't - mess with its lifetime. Nor do we need to worry about leaking things, so long as we leave take_copy = false. Then we just call wrap() whenever we want to create-or-get a wrapper for a C instance, and don't worry about it.


It would be nice to make this explicit in the docs; I'll write a small patch. The page I came from is this - https://developer.gnome.org/gtkmm-tutorial/stable/sec-basics-gobj-and-wrap.html.en - and could do with being slightly less terse.


_______________________________________________
gtkmm-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtkmm-list