Re: Gtk-- refcounting question




Sebastian Wilhelmi <wilhelmi@ira.uka.de> writes:

> Hi, Owen
> 
> the points, that I was trying to make, was the following:
> 
> 1. If I create a Gtk_Object (C++, that is), it should live exactly until
> I destroy it. That breaks down into: It will not be deleted, even if the
> C-Part is def-refcounted to 0 (e.g. I might want to reparent)(so that
> means refcount up by 1 in the C++-constructor). And it should disappaer,
> when I destroy it. If I got it right, you're saying, that the C++-Part
> can not tell gtk to destroy the object, because gtk might still have
> some references to it?? In that case it should at least be destroyed (in
> the sense you said -- unmapped) and C++ should be unable to reference it
> any more. 

The C object will be destroyed when it gets refcounted to zero -
and there is nothing you can do about it.

In the C interface to GTK, it is necessary to do:

   gtk_widget_ref (child);
   gtk_container_remove (parent, child);
   gtk_container_add (parent2, child);
   gtk_container_unref (child)


> I am rather unsure, if you can simply use the C-refcounting in C++ to
> achieve something like "smart pointers", because a C++-programmer would
> again expect a window, he has two smart-pointers to, to be destroyed, if
> he destroys both. So C++ would IMHO have to do a second layer of
> ref-counting.

That programmer needs to learn how the system works. gtk-- should
_not_ have to keep pointers explicitly around to every widget that has
been added to the widget heirarchy. That just makes writing
applications much more complicated.

I don't think the programmer that does:

  { 
    Gtk_Object_var button = new Gtk_Button ("Close");
    parent->add (button);
  }

expects the button to be immediately destroyed. Or at least,
I think they would be very happy to find out that it isn't.
Quite a bit of effort was put into the referencing counting
system so this type of thing can work. It might as well
be used in C++.

The beauty of referencing counting is that you only need to care about
what you are doing with an object and not about what other people are
doing with an object.


If you insist on referencing counting the C++ object and the C
object separately, then you have to live with some consequences.

 The C++ object must last as long as the C object, because the C
   object can be implemented in the C++ object.

 The objects can't mutually hold reference counts on each other,
   because that will result in neither ever being freed.

Therefore, unless you split the C++ object into two parts.
(The implementation, and the reference to the C object), the
C++ object cannot hold a reference count on the C object, and
your user has to worry about the referencing counting for
the C object as well as that for the C++ object.

Because you are implemented referencing counting in C++ yourself,
there is no reason to go through this hassle - you can just use
the C referencing counting for both.
 
[ This situation does arise for for other languages which have
  built in reference counting. guile-gtk doesn't allow deriving
  from C objects, while I think the Gtk module for Perl is
  going to go with the split object setup ]

> I also dont't think, that ref-counting should be visible in C++ at all.
> C++ is (through the automatic destructor call on deletion) able to
> handle this in a far more elegant way (using smart-pointer), just like
> your CORBA-example. I suspect, thats why it is called _duplicate, not
> ref, because the "unref" is (I suspect, not know, so correct me ;-) done
> automatically by the destructor.

In CORBA _duplicate basically is a ref() and release() an unref().
There is no requirement that you use the smart pointer system, and
it is sometimes convenient not to use this. 

If you are using smart pointers, you can basically forget about
the reference counting, but not really. C++ is never going to
hide things so well that there won't be some subtle traps, so
I think it is better, instead of trying to make it as invisible
as possible, to make it as simple as possible (while still
maintaining the convenience), so that users _can_ understand it.

But, even if you are trying for complete invisibility (which
is just means that the user has to learn magic incantations they
don't understand), I think reference counting based on the C
reference counting should work.

(To play Devil's advocate to my own scheme, here is what is 
 probably the biggest problem with CORBA style reference counting in C++:

 Note that, unlike C referencing counting, the C++ reference counting
 has to be mandatory, for things to work out properly.

 That is, in C, both:

   GtkWidget *w = GTK_BIN(button)->child;
   gtk_object_destroy (GTK_OBJECT (w)); // *w is freed in call

 and

   GtkWidget *w = GTK_BIN(button)->child;
   gtk_widget_ref (w);
   gtk_object_destroy (GTK_OBJECT (w));
   gtk_widget_unref (w); // *w is freed here

 are valid. (Above comments assume no other reference counts to *w
 are held.)

 But, you can't have both:

 {
  Gtk_Widget_var w = button->child();
  w->destroy();
 }

 and

 {
  Gtk_Widget *w = button->child();
  w->destroy();
 }

 work. Because the C++ object for w can't be destroyed in the call
 to w->destroy(). That is, the automatic pointer can't add _another_
 reference count to w - instead, every function that returns a 
 Gtk_Object must increment the reference before returning it.

 Which means that:

  button->child()->destroy()

 will be a memory leak. (unless Gtk_Bin::child() actually returns
 a Gtk_Widget_var& instead of a Gtk_Widget * - CORBA doesn't
 do this, probably for reasons of efficiency.))

If you are interested in referencing counting in GTK, at the
nitty-gritty level, you should certainly take a look at
docs/refcounting.txt.
  
Regards,
                                        Owen



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]