簡體   English   中英

Gtkmm 添加/刪除小部件泄漏 為什么?

[英]Gtkmm add/Remove widget leaks Why?

當我將小部件添加到容器時,我將其刪除。 微件泄露了,為什么? 我使用“MyWidget”來監視小部件刪除,但我從經典的 Gtk::Label 得到了相同的結果。 下面的代碼已經在兩個發行版上進行了測試。

#include <iostream>
// gtkmm30-3.24.5-1.el9.x86_64
// or gtkmm3 3.24.7-1 (arch)
#include <gtkmm/main.h>
#include <gtkmm/builder.h>
#include <gtkmm/label.h>
#include <gtkmm/window.h>
#include <gtkmm/box.h>

#include <cassert>

using namespace std;

class MyWidget : public Gtk::Label{
public:
    MyWidget(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder);
    virtual ~MyWidget();
};

MyWidget::~MyWidget(){
    cout << "MyWidget::~MyWidget()" << endl;
}

MyWidget::MyWidget(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder)
 : Gtk::Label(cobject)
{
    assert(builder);
}

int main()
{
    Gtk::Main main;
    
    // Create widget
    auto builder = Gtk::Builder::create_from_file("widget.glade");
    MyWidget* widget = nullptr;
    builder->get_widget_derived("widget", widget);

    {
        Gtk::Window window;
        window.add(*widget);
        // Use window ....
        window.remove(); // No leak if this line is commented
    }
    
    builder.reset();
    cout << G_OBJECT(widget->gobj())->ref_count << endl; // Print => 1
    // Expected to see "MyWidget::~MyWidget()" but No ! Why ?
}

我希望看到 ~MyWidget 析構函數被執行。

這是我的空地文件內容

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.40.0 -->
<interface>
  <requires lib="gtk+" version="3.24"/>
  <object class="GtkLabel" id="widget">
    <property name="visible">True</property>
    <property name="can-focus">False</property>
    <property name="label" translatable="yes">widget</property>
  </object>
</interface>

我們在這里做出的錯誤假設是Gtk::Window::remove()破壞了它移除的小部件,但實際上,它只是從父容器中移除了它的引用。 我用額外的cout檢測了您的代碼,以查看發生了什么以及何時執行此行:

builder->get_widget_derived("widget", widget);

MyWidget實例由構建器創建。 此時,構建器擁有對它的引用並且引用計數為 1。 然后,當執行以下行時:

window.add(*widget);

正如您所指出的,window 是一個單元素容器, MyWidget實例進行(擁有)引用。 所以MyWidget實例上的引用計數現在是 2:一個用於構建器,一個用於 window。這就是它變得棘手的地方。 執行時:

window.remove();

window“刪除”了它對MyWidget實例的引用,從某種意義上說,它將不再show它,但它的引用計數不會減少。 此時, MyWidget實例上仍然有兩個引用:一個用於構建器,另一個不屬於任何人(它被泄露,除非有人明確地對其調用delete )。 執行此行時:

builder.reset();

構建器被銷毀,它對MyWidget實例的引用被刪除,使它的引用計數變為 1。 這就是為什么在您的案例中打印引用計數總是打印“1”的原因。

現在,如果我們注釋掉:

window.remove();

main結束時會發生什么, window 銷毀自身及其引用的小部件(如果有)。 在您的情況下,這是MyWidget實例,因此調用析構函數並將引用計數設為 0。您看不到它被打印出來,因為它發生在cout調用之后,在} (scope 的末尾,對於main )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM