Any thoughts on this C++ smart pointer issue?
jcfranks at tpg.com.au
Sun Nov 28 21:58:47 CET 2004
Brian J. Tarricone wrote:
> i like choice. choice is good. it's always nice to have choice.
> having said that, i feel like one of the bonuses/benefits of using a
> c++ wrapper like Gtkmm or XFC is that a good number of the annoyances
> with gtk's C-based OO API disappear, one of those being refcount
> management (for objects like in this case). i tend to think that, a
> programmer, when choosing something like gtkmm or XFC, will implicitly
> agree to the premise that they're getting a better abstraction and a
> toolset that's a little easier to work with, at the expense of some
> amount of performance (and/or memory usage?).
> personally, i would just use the smart pointers all the time, unless i
> later find that i can greatly enhance performance in portions of my
> code by not doing so. premature optimisation is the root of all
> (most) evil.
> so my feeling is that it's great to have that choice there, but i
> think that the use of "the old way" should be discouraged (in the same
> sense that accessing the raw C GObject pointer in gtkmm is discouraged).
> that's just how i feel about it; jeff, it's your show, and you know
> the implementation details, so it's of course ultimately up to you.
Most objects dealt with are widgets and these don't require smart
pointers because you can add them to a container and the container
manages the reference counting issues. In situation I felt that smart
pointers would be overkill.
>> Compared with Gtkmm, you can create and use a Xfc::Gtk::AccelGroup
>> either like this:
>> Pointer<Gtk::AccelGroup> accel_group = new Gtk::AccelGroup;
>> // use accel_group, it is unreferenced when it goes out of scope
>> or like this:
>> Gtk::AccelGroup *accel_group = new Gtk::AccelGroup;
>> // use accel_group
> ok, i'm slightly confused now. for the first example, is that
> correct, or should it be "= Gtk::AccelGroup::create();"?
This example is for XFC and it is right for Gtk::AccelGroup. XFC uses
create functions, but only when the return value from g_object_new()
might be NULL, like some of the GdkPixbuf '_new' functions. In this case
the Gdk::Pixbuf class provides create fuctions if NULL might be returned
and public constructors if NULL can never be returned. This prevents an
exception being thrown in the constructor.
>> The only disadvantage with this approach is that it requires the
>> programmer to be aware of the class a new object derives from:
>> Xfc::G::Object (never floating) or Xfc::Gtk::Object (floating). All
>> the reference counting rules are identical to GTK+. So if you pass a
>> floating object to an owner, or add a widget to a container, you
>> don't need to worry about reference counting or smart pointers. If
>> you pass a G::Object to an owner, like a Gtk::AccelGroup to a window,
>> you have to explicitly unreference it after if you are not using a
>> smart pointer. This only applies to object construction. All class
>> methods that return a pointer to an object that must be unreferenced
>> return as a smart pointer.
> i think this is fine. i think most gtk programmers that have dealt
> with these issues already know how gtk's floating references work, and
> that they're unique to classes that inherit from GtkObject. so as
> long as the semantics are the same as the C interface (as you point
> out), i think we're ok here. the win here is that new XFC programmers
> don't have to learn any new semantics if they don't want to: they can
> just continue to do things in the same way as when they used the C
> APIs. actually, this is another argument for keeping the choice of
> smart pointer vs. manual memory management. of course, prominently
> advocating the use of the smart-pointer interface in the API docs is a
> must, IMO.
Memory management in XFC can leak - but this is only releative not
absolute. By that I mean that all raw un-deleted memory allocations are
reclaimed when a program exits, but not while a program is running. This
is obviously not garabge collection but rather a simple way to reclaim
the memory allocated to objects that wrap global GTK objects that are
not destroyed by GTK until GTK is removed from memory. If you run GNOME
or Xfce, the GTK libraries are never removed from memory until GNOME or
Xfce is shut down. XFC relies on the GTK object's destroy signal to know
when a C object is destroyed and its C++ wrapper can be deleted. This
notification never occurs for global GTK objects until GTK+ is removed
from memory. There are many global GTK objects so the potential memory
leak over time can be significant. If a XFC program ran for a long time
the memory would appear to leak if the programmer doesn't manage memory
properly but as soon as that program is shut down the leaked memory
would be recovered, so the leak is only relative, while the program is
running, and not absolute. When you recover raw memory an object's
destructor doesn't get called.
The purpose of that rant is this. The only place a programmer might not
manage memory properly is with a G::Object (like Gtk::AccleGroup) that
has an initial reference that must be released. Gtkmm forces the
programmer to use smart pointers in these cases so it is not an issue.
Currently, XFC provides public constructors and relies on the programmer
either choosing to use a smart pointer (the first example, by
assignment, I know a possible sin) or by using a dumb pointer and
calling unref() when the dumb pointer is no longer needed.
I really feel that enforcing the use of smart pointers for floating
objects is overkill since you must pass a Gtk::Object to some owner
object or add a Gtk::Widget to a container. In both cases all reference
counting issues are managed automatically. I do concede that closing the
'memory leak' loophole for G::Objects and enforcing the use with smart
pointers (like Gtkmm) might be a better option. If I do this, then
essentially the only way a programmer could leak memory (relatively,
while a program is running) is to create a floating object and never
pass it to an owner object or container (which is plain stupid).
I do want to get XFC right so I'm happy to make this change if you think
it would be better.
More information about the Xfce4-dev