问题
The guys from Gtkmm are comparing Glib::RefPtr
with std::auto_ptr<>
:
Glib::RefPtr
is a smartpointer. Specifically, it is a reference-counting smartpointer. You might be familiar withstd::auto_ptr<>
, which is also a smartpointer, butGlib::RefPtr<>
is much simpler, and more useful.
But for some strange reason, I can't get my work done with the RefPtr
. The same code is just fine with a auto_ptr
.
In the following code, SmartPtr
is just a placeholder for one of these two smartpointers.
#include <gtkmm.h>
#include <iostream>
#include <tr1/memory>
struct WindowHolder {
SmartPtr<Gtk::Window> ptr;
WindowHolder()
: ptr(new Gtk::Window)
{
ptr->signal_delete_event().connect(sigc::mem_fun(*this, &WindowHolder::reset));
ptr->show_all();
}
bool reset(GdkEventAny* event)
{
Gtk::Main::quit();
}
};
int main(int argc, char *argv[])
{
Gtk::Main kit(argc, argv);
WindowHolder w;
kit.run();
}
When compiling, I first define SmartPtr
as Glib::RefPtr
and then as std::auto_ptr
.
$ g++ '-DSmartPtr=Glib::RefPtr' `pkg-config --cflags --libs gtkmm-3.0` main.cc && ./a.out
(main:22093): GLib-GObject-CRITICAL **: g_object_unref: assertion `G_IS_OBJECT (object)' failed
$ g++ '-DSmartPtr=std::auto_ptr' `pkg-config --cflags --libs gtkmm-3.0` main.cc && ./a.out
$
The problem is this GLib-GObject-CRITICAL
. In my real application, this isn't just a single line but a whole bunch of them. In the second version with std::auto_ptr
everything gets destructed well.
Strange enough the code it is just fine in GTK 2:
$ g++ '-DSmartPtr=Glib::RefPtr' `pkg-config --cflags --libs gtkmm-2.4` main.cc && ./a.out
$
I don't want to depend on std::auto_ptr
because it is deprecated and I also don't want to work with a raw pointer because then the destructors have to manually delete the pointers which adds extra complexity ...
My questions are:
- Why causes
Glib::RefPtr
this "critical warning" (probably a double free)? - Why does it work with gtkmm 2.4 but not in 3.0?
- Can I fix the code with
Glib::RefPtr
and gtkmm 3.0? - How should I handle such situations in general?
回答1:
The reference count is too low, and you can fix it by adding a ptr->reference()
after ptr->show_all()
. I have an explanation, but take it with a grain of salt:
- Glib::RefPtr doesn't increment the reference count of its object initially.
- The GtkWindow will have a reference count initially of 1.
- When your window is closed, the library decrements the reference count of its GtkWindow once.
- Since the GtkWindow's count is zero, it is destroyed.
- kit.run() seeing there is no more windows, returns.
- w goes out of scope and the RefPtr's object's count is decremented causing the error.
I can't really answer #2 or #4 unfortunately, as this area of gtk/gtkmm is still a little mysterious (to me).
Reference: http://www.gtkforums.com/viewtopic.php?t=2412
回答2:
Glib::RefPtr is not meant to be for general use. You should use it when the API forces you to, but not otherwise. GtkWindow (or Gtk::Window) has its own odd memory management which is not really compatible with RefPtr.
If you want a general purpose smartpointer, try std::shared_ptr or std::unique_ptr. Or you could find something in boost.
来源:https://stackoverflow.com/questions/10156565/destructing-glibrefptr-causes-failed-assertions-in-the-gtk-3-core