当我添加一个小部件到容器,然后我删除它。小部件泄漏,为什么?我用“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析构函数被执行。
这是我的glade文件内容
<?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>
1条答案
按热度按时间yeotifhr1#
我们在这里做了一个错误的假设,即
Gtk::Window::remove()
破坏了它所删除的小部件,但实际上,它只是删除了它对父容器的引用。我用额外的cout
来检测代码,以查看发生了什么以及何时执行了这一行:生成器创建了一个
MyWidget
示例。此时,生成器拥有对它的引用,引用计数为1。然后,当执行以下代码行时:这个窗口是一个元素容器,正如您所指出的,它在
MyWidget
示例上有一个引用,所以MyWidget
示例上的引用计数现在是2:一个用于构建器,一个用于窗口。这就是它变得棘手的地方。当执行时:该窗口“移除”其对
MyWidget
示例的引用,意思是它将不再对show
示例进行show
,但其上的引用计数不递减。此时,在MyWidget
示例上仍存在两个引用:一个用于构建器,另一个不为任何人所有(除非有人显式地对它调用delete
,否则它是泄漏的)。构建器被销毁,它对
MyWidget
示例的引用被删除,使其引用计数为1。这就是为什么在您的情况下打印引用计数总是打印“1”。现在如果我们注解出:
如果在
main
结束时,窗口销毁自身及其引用的小部件,会发生什么情况(如果有的话)。在您的例子中,这是MyWidget
示例,因此析构函数被调用,引用计数被置为0。您看不到它,因为它发生在cout
调用之后,在}
(main
的作用域结尾)。