[英]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.