2012-04-14 8 views
7

I ragazzi di Gtkmm sono comparingGlib::RefPtr con std::auto_ptr<>:Distruzione Glib :: RefPtr provoca fallito affermazioni nel nucleo GTK 3

Glib::RefPtr è una smart pointer. In particolare, è uno smartpointer conteggio di riferimento. Si potrebbe avere familiarità con std::auto_ptr<>, che è anche uno smartpointer, ma Glib::RefPtr<> è molto più semplice e più utile.

Ma per qualche strano motivo, non riesco a terminare il lavoro con lo RefPtr. Lo stesso codice va bene con uno auto_ptr.

Nel seguente codice, SmartPtr è solo un segnaposto per uno di questi due smartpoint.

#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(); 
} 

Quando si compila, in primo luogo ho definisco SmartPtr come Glib::RefPtr e poi come 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 
$ 

Il problema è questo GLib-GObject-CRITICAL. Nella mia vera applicazione, questa non è una singola riga ma un intero gruppo di essi. Nella seconda versione con std::auto_ptr tutto viene distrutto bene.

abbastanza strano il codice è proprio bene in GTK 2:

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

Non voglio dipendere da std::auto_ptr perché è deprecato e ho anche non voglio lavorare con un puntatore cruda perché poi i distruttori devono eliminare manualmente i puntatori che aggiunge ulteriore complessità ...

le mie domande sono:

  1. Perché provoca Glib::RefPtr questa "critica l avvertimento "(probabilmente un doppio libero)?
  2. Perché funziona con gtkmm 2.4 ma non in 3.0?
  3. Posso correggere il codice con Glib::RefPtr e gtkmm 3.0?
  4. Come devo gestire tali situazioni in generale?

risposta

4

Il conteggio di riferimento è troppo bassa, e si può risolvere il problema con l'aggiunta di un ptr->reference() dopo ptr->show_all(). Ho una spiegazione, ma prendila con un pizzico di sale:

  • Glib :: RefPtr non incrementa il conteggio dei riferimenti del suo oggetto inizialmente.
  • GtkWindow avrà inizialmente un conteggio di riferimento 1.
  • Quando la finestra è chiusa, la libreria decrementa il conteggio dei riferimenti della sua GtkWindow una volta.
  • Poiché il conteggio di GtkWindow è zero, viene distrutto.
  • kit.run() vedendo che non ci sono più finestre, restituisce.
  • w esce dal campo di applicazione e il conteggio dell'oggetto RefPtr viene decrementato causando l'errore.

Purtroppo non posso davvero rispondere n. 2 o n. 4, poiché quest'area di gtk/gtkmm è ancora un po 'misteriosa (per me).

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

5

Glib :: RefPtr non è destinata ad essere per uso generale. Dovresti usarlo quando l'API ti costringe a farlo, ma non altrimenti. GtkWindow (o Gtk :: Window) ha una sua gestione di memoria dispari che non è realmente compatibile con RefPtr.

Se si desidera uno smartpointer generico, provare std :: shared_ptr o std :: unique_ptr. O potresti trovare qualcosa in più.

+0

Grazie per aver chiarito questo. – glitto

+0

Non 'Glib :: RefPtr' utilizza il conteggio dei riferimenti interno' GObject'? –

+0

@ el.pescado [Controlla la documentazione] (https://developer.gnome.org/glibmm/stable/classGlib_1_1RefPtr.html#details): "_RefPtr <> può memorizzare qualsiasi classe che abbia metodi reference() e unreference() e il cui distruttore è senza eccezioni (il default per i distruttori). In gtkmm, questo è tutto derivato da Glib :: ObjectBase, come Gdk :: Pixmap._ "Quindi, sì. È un puntatore intelligente intrusivo destinato esclusivamente a 'GObject's avvolti, sfruttando il conteggio dei riferimenti preesistente. Piuttosto che avvolgere il proprio 'GObject's con esso, ho l'impressione che sia solo un dettaglio di implementazione delle librerie' mm'. –