【问题标题】:gtkmm: what is Glib::RefPtr usecases?gtkmm:什么是 Glib::RefPtr 用例?
【发布时间】:2019-07-07 15:14:12
【问题描述】:

我正在用 C++ 和 gtkmm 库编写一个小 GTK3 应用程序。

在 gtkmm 文档中,通常会使用一些具体实例,例如 Gtk::Application、Gtk::Builder、Gtk::StatusIcon 等。使用 create() 静态方法初始化,这些方法返回 Glib::RefPtr。同时子小部件通常只出现在堆栈上。

这对我来说不是很清楚:

  • 是因为内存堆栈使用还是其他原因?目前我的代码中没有 RefPtr。我使用 valgrind 的 massif 工具检查了堆栈的使用情况,峰值使用量约为 100 KB。对我来说似乎不算太低,但相当大小的 example with RefPtr's 占用相同的堆栈内存。
  • 我可以像 Application myapp 那样将所有实例都放在堆栈上,还是应该在它存在时始终使用 create()?
  • 在这种情况下,指针提供了哪些优势?

【问题讨论】:

    标签: c++ pointers gtkmm


    【解决方案1】:

    Glib::RefPtr 是一个引用计数的智能指针,早于std::shared_ptr 并执行相同的基本功能。它的用例是相似的——它允许多个对象想要共享一个对象的所有权,而无需直接相互了解。

    在您的具体示例中,可能会共享一个图标,因为它在 UI 中的多个位置使用,并且您不希望维护相同图像数据的多个副本,如果存在可能会占用大量内存有很多图标。

    ApplicationBuilder 对象可能由程序中的多个对象持有(例如,不同的窗口或对话框对象),因此只要其中一个对象仍在使用它,引用计数就会使每个对象保持活动状态。这使Application 对象的这些用户不必了解可能使用共享Application 对象的程序的所有其他部分。当一个窗口使用Application 完成时,它会破坏其指向Application 的智能指针。如果该窗口是最后一个所有者,这也会破坏 Application 对象,但否则它会为其他用户保持活动状态——所有这些都不会让您被破坏的窗口知道 Application 是否存在。

    【讨论】:

    • 感谢您简短而明确的回答,@metal!但是,当我们谈论 C++ 时,为什么不直接在这些共享对象上传递引用呢?还是对象的生命周期是原因?
    • 是的,就是管理生命周期。如果您传递引用,它们可能会变得悬空并导致未定义的行为,因为程序的某些其他部分会删除该对象(或者它超出范围,如果它在堆栈上)。通过引用计数共享所有权允许程序的不同部分共享所有权并使其保持活动状态,而无需直接相互了解。
    【解决方案2】:
    • 是因为内存堆栈使用还是其他原因?目前我的代码中没有 RefPtr。我用 valgrind's 检查了堆栈的使用情况 massif 工具,峰值使用量约为 100 KB。对我来说似乎不算太低, 但可比较的大小 [RefPtr 的示例][1] 需要相同的一块 堆栈内存。

    主要原因是 gtkmm 是对用 C 编写的 Gtk+ 库的精简 C++ 包装器。Gtk+ 中的大多数对象都是在堆上分配的(例如,GtkApplication 对象是使用 gtk_application_new 函数创建的),并且是引用计数的(手动,使用g_object_ref/g_object_unref 函数)。换句话说,这些对象已经共享指针语义,尽管用纯 C 表示。因此,在 C++ 中将这些对象表示为智能指针是最有意义的——在这种情况下是 Glib::RefPtr。

    • 我可以像 Application myapp 那样将所有实例都放在堆栈上,还是应该在它存在时始终使用 create()?

    不,因为Gtk::Application 构造函数是protected,所以编译器不允许在堆栈上创建这些对象。

    • 在这种情况下,指针有什么优势?

    我认为情况正好相反。将这些对象保留在堆栈上不会带来任何好处,因为由 gtkmm 对象包装的 Gtk 对象本质上是共享指针。

    【讨论】:

    • 看起来很合理。但是为什么 gtkmm 不为一些更紧凑和灵活的代码隐藏 Glib 的共享指针(例如,如果有人想使用某种 boost 的指针)?是因为避免开销吗?而且我无法理解共享指针如何帮助我处理生命周期符合程序生命周期的对象。
    • 不可能取消引用 RefPtr 以传递给例如add_window(Window &)。我检查了the example。因此,示例的窗口create 方法返回一个指针(只是指针,而不是RefPtr)。我应该说这对我来说太令人沮丧了,因为我完全困惑什么时候应该使用 RefPtrs,什么时候应该使用“普通”指针以及为什么我不应该只使用引用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    • 2015-05-01
    相关资源
    最近更新 更多