2012-04-14 4 views
7

Die Jungs von Gtkmm sind comparingGlib::RefPtr mit std::auto_ptr<>:Destructing Glib :: RefPtr verursacht gescheitert Behauptungen in der GTK 3 Kern

Glib::RefPtr ein Intelligenter Zeiger ist. Insbesondere ist es ein Referenzzähler Smartpointer. Sie kennen vielleicht std::auto_ptr<>, die auch ein Smartpointer ist, aber Glib::RefPtr<> ist viel einfacher und nützlicher.

Aber aus irgendeinem seltsamen Grund kann ich meine Arbeit nicht mit der RefPtr erledigen. Der gleiche Code ist in Ordnung mit einem auto_ptr.

Im folgenden Code ist SmartPtr nur ein Platzhalter für einen dieser beiden 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(); 
} 

Beim Kompilieren definiere ich zunächst SmartPtr als Glib::RefPtr und dann als 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 
$ 

Das Problem ist dieses GLib-GObject-CRITICAL. In meiner realen Anwendung ist dies nicht nur eine einzelne Zeile, sondern eine ganze Reihe von ihnen. In der zweiten Version mit std::auto_ptr wird alles gut zerstört.

Seltsam genug, um den Code, um es in GTK nur gut 2:

$ g++ '-DSmartPtr=Glib::RefPtr' `pkg-config --cflags --libs gtkmm-2.4` main.cc && ./a.out 
$ 

Ich mag nicht auf std::auto_ptr abzuhängen, weil es veraltet ist, und ich will auch nicht mit einem rohen Zeiger arbeiten, weil dann haben die Destruktoren manuell die Zeiger zu löschen, die zusätzliche Komplexität hinzufügt ...

Meine Fragen sind:

  1. Warum verursacht Glib::RefPtr diese „critica l warning "(wahrscheinlich ein Doppel kostenlos)?
  2. Warum funktioniert es mit gtkmm 2.4 aber nicht in 3.0?
  3. Kann ich den Code mit Glib::RefPtr und gtkmm 3.0 beheben?
  4. Wie soll ich generell mit solchen Situationen umgehen?

Antwort

4

Der Referenzzähler ist zu niedrig, und Sie können das Problem beheben, indem ein ptr->reference() nach ptr->show_all() Zugabe. Ich habe eine Erklärung, aber nehmen Sie es mit einem Körnchen Salz:

  • Glib :: RefPtr erhöht nicht die Referenzzahl seines Objekts anfänglich.
  • Das GtkWindow hat anfänglich eine Referenzzählung von 1.
  • Wenn Ihr Fenster geschlossen ist, dekrementiert die Bibliothek die Referenzzählung ihres GtkWindow einmal.
  • Da die Anzahl der GtkWindows null ist, wird sie zerstört.
  • kit.run() zu sehen, gibt es keine Fenster mehr, kehrt zurück.
  • w überschreitet den Gültigkeitsbereich und die Anzahl der RefPtr-Objekte wird verringert, wodurch der Fehler verursacht wird.
  • Ich kann leider nicht wirklich # 2 oder # 4 beantworten, da dieser Bereich von gtk/gtkmm immer noch ein wenig mysteriös ist (für mich).

    Referenz: http://www.gtkforums.com/viewtopic.php?t=2412

    5

    Glib :: RefPtr ist nicht für den allgemeinen Gebrauch sein soll. Sie sollten es verwenden, wenn die API Sie zwingt, aber nicht anders. GtkWindow (oder Gtk :: Window) hat seine eigene ungerade Speicherverwaltung, die nicht wirklich mit RefPtr kompatibel ist.

    Wenn Sie einen universellen Smartpointer verwenden möchten, versuchen Sie std :: shared_ptr oder std :: unique_ptr. Oder du könntest etwas im Boost finden.

    +0

    Danke für die Klärung. – glitto

    +0

    Verwendet 'Glib :: RefPtr' nicht die interne' GObject' Referenzzählung? –

    +0

    @ el.pescado [Überprüfen Sie die Dokumentation] (https://developer.gnome.org/glibmm/stable/classGlib_1_1RefPtr.html#details): "_RefPtr <> kann jede Klasse speichern, die reference() - und referenz() -Methoden hat , und dessen Destruktor ist kein except (der Standard für Destruktoren). In gtkmm, das ist alles aus Glib :: ObjectBase abgeleitet, wie Gdk :: Pixmap._ "Also ja. Es ist ein intrusiver Smart-Pointer, der nur für gepackte 'GObjects' gedacht ist, die ihre bereits vorhandene Referenzzählung nutzen. Anstatt die eigenen 'GObject' damit zu verpacken, habe ich den Eindruck, dass es nur ein Implementierungsdetail der' mm' Bibliotheken ist. –