破坏 Glib::RefPtr 会导致 GTK 3 核心中的断言失败

Posted

技术标签:

【中文标题】破坏 Glib::RefPtr 会导致 GTK 3 核心中的断言失败【英文标题】:Destructing Glib::RefPtr causes failed assertions in the GTK 3 core 【发布时间】:2012-04-14 19:17:23 【问题描述】:

来自 Gtkmm 的人是 comparing Glib::RefPtrstd::auto_ptr<>

Glib::RefPtr 是一个智能指针。具体来说,它是一个引用计数智能指针。您可能对std::auto_ptr<> 很熟悉,它也是一个智能指针,但Glib::RefPtr<> 更简单,也更有用。

但由于某些奇怪的原因,我无法使用RefPtr 完成我的工作。 auto_ptr 也可以使用相同的代码。

在以下代码中,SmartPtr 只是这两个智能指针之一的占位符。

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

编译时,我先定义SmartPtrGlib::RefPtr,再定义为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 
$

问题是这个GLib-GObject-CRITICAL。在我的实际应用程序中,这不仅仅是一行,而是一大堆。在带有std::auto_ptr 的第二个版本中,一切都被很好地破坏了。

足够奇怪的代码在 GTK 2 中就可以了:

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

我不想依赖std::auto_ptr,因为它已被弃用,而且我也不想使用原始指针,因为这样析构函数必须手动删除指针,这会增加额外的复杂性......

我的问题是:

    为什么会导致Glib::RefPtr 这个“严重警告”(可能是双重免费)? 为什么它适用于 gtkmm 2.4 而不适用于 gtkmm 3.0? 我可以用Glib::RefPtr 和gtkmm 3.0 修复代码吗? 一般我应该如何处理这种情况?

【问题讨论】:

【参考方案1】:

Glib::RefPtr 不适合一般用途。当 API 强制您使用时,您应该使用它,但不是其他情况。 GtkWindow(或 Gtk::Window)有自己的奇数内存管理,与 RefPtr 并不真正兼容。

如果你想要一个通用的智能指针,试试 std::shared_ptr 或 std::unique_ptr。或者你可以在 boost 中找到一些东西。

【讨论】:

Glib::RefPtr 不使用内部 GObject 引用计数吗? @el.pescado Check the documentation: "RefPtr 可以存储任何具有 reference() 和 unreference() 方法的类,并且其析构函数为 noexcept(析构函数的默认值)。在 gtkmm 中,这是从 Glib::ObjectBase 派生的任何东西,例如 Gdk::Pixmap。" 所以,是的。这是一个侵入式智能指针,仅用于包装的GObjects,利用其预先存在的引用计数。我没有用它包装自己的GObjects,而是觉得它只是mm 库的一个实现细节。【参考方案2】:

引用计数太低,您可以通过在ptr-&gt;show_all() 后添加ptr-&gt;reference() 来修复它。我有一个解释,但持保留态度:

Glib::RefPtr 最初不会增加其对象的引用计数。 GtkWindow 最初的引用计数为 1。 当您的窗口关闭时,库会减少其 GtkWindow 的引用计数一次。 由于 GtkWindow 的计数为零,它被销毁。 kit.run() 看到没有更多的窗口,返回。 w 超出范围并且 RefPtr 的对象计数减少,从而导致错误。

不幸的是,我无法真正回答 #2 或 #4,因为 gtk/gtkmm 的这个区域仍然有点神秘(对我来说)。

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

【讨论】:

以上是关于破坏 Glib::RefPtr 会导致 GTK 3 核心中的断言失败的主要内容,如果未能解决你的问题,请参考以下文章

如何获取 gtktreeview 标头的高度?

是啥导致不同 GTK 版本之间 GtkIconView 的显示行为不同?

如何从OpenGL加载图像?

实例化 GameObject 会导致所述对象的 Transform 被破坏?

Gtksharp编译时提示下载gtk文件问题

使用 Gtk::Viewport (gtkmm3) 直接滚动