【问题标题】:Is HelloWindow object deleted?HelloWindow 对象是否被删除?
【发布时间】:2020-08-27 12:59:32
【问题描述】:

我在 GNOME Builder 上创建了一个示例 GTKMM 项目。最棒的是,为我的示例项目自动生成了一个示例 hello world 代码。由于 C++ 源文件被组织成三个部分:

  • 头文件
  • 实施文件
  • 主文件

我已在单个 cpp 文件中修改了我的示例代码以进行演示:

#include <iostream>

#include <gtkmm.h>

using std::cout;

using Gtk::Application;
using Gtk::Window;
using Gtk::Box;
using Gtk::Button;
using Gtk::Label;

class HelloWindow : public Window
{
    Box    box;
    Button button;
    Label  label;

public:
    HelloWindow();
    ~HelloWindow();
};

HelloWindow::HelloWindow()
    : Glib::ObjectBase("HelloWindow")
    , Window()
    , box(Gtk::ORIENTATION_VERTICAL)
    , button("Clickable button")
    , label("Hello World!")
{
    set_default_size(320, 240);

    bool expand(true), fill(true);
    box.pack_start(label, expand, fill);
    box.pack_end(button, expand, fill);

    add(box);

    show_all();
}

HelloWindow::~HelloWindow()
{
    cout << "Object successfully destructed!\n";
}

static void
on_activate(Glib::RefPtr<Application> app)
{
    Window *window = app->get_active_window();

    if (not window) {
        window = new HelloWindow();
        window->set_application(app);
        app->add_window(*window);
    }

    window->present();
}

int main()
{
    auto app = Application::create("io.test.window-state-event");

    app->signal_activate().connect(sigc::bind(&on_activate, app));

    return app->run();
}

关于上述代码的一个有趣的部分是app 连接到on_activate 信号,这意味着用户只能运行该程序的一个实例。如果他尝试运行另一个实例,则会显示之前仍在运行的窗口。

但是,on_activate() 上使用了 new 关键字,这让我有点困惑。当用户关闭 HelloWorld 窗口时,对象真的被删除了吗?我对 C++ new 关键字的了解是,必须记住 delete 使用前一个关键字分配的任何对象。

此外,析构函数消息“对象已成功销毁!”关闭窗口时不打印。

【问题讨论】:

    标签: c++ oop gtkmm3


    【解决方案1】:

    可能存在故意泄漏,但它是“可控的”。作者知道这个方法只会被调用一次。作者还知道内存需要在应用程序的整个生命周期内处于活动状态。当应用程序关闭时,该内存将以一种或另一种方式释放(尽管永远不会调用析构函数,但在这种情况下,不需要做任何必要的事情)

    这个场景中完全没问题。

    如果您想确保删除Window 对象,您可以保留Windowunique_ptr,它会自行处理(感谢@underscore_d 评论):

    #include <memory>
    
    static std::unique_ptr<Window> window;
    
    static void
    on_activate(Glib::RefPtr<Application> app)
    {
        if (!window) {
            window = std::make_unique<HelloWindow>();
            window->set_application(app);
            app->add_window(*window);
        }
    
        window->present();
    }
    
    int main()
    {
        auto app = Application::create("io.test.window-state-event");
        app->signal_activate().connect(sigc::bind(&on_activate, app));
        return app->run();
    }
    

    归根结底,我确信作者希望让这个“Hello, World”示例保持简单明了,不想添加一些真正不需要的代码> 在那里是为了保持简单和简洁。

    【讨论】:

    • static std::unique_ptr&lt;Gtk::Window&gt;(在命名空间范围内或只是在函数中)应该是一种更简单的方法来满足跟踪窗口是否存在的愿望运行析构函数,每个进程一次。就个人而言,我在不太明确的情况下做了更复杂的事情,比如制作std::shared_ptr&lt;Gtk::Window&gt;,在作为Application::shutdown 的信号处理程序的lambda 中捕获它,并在执行所述lambda 时将其删除......但是在这个情况下,这可能是过度工程。
    • @underscore_d -- 但在这种情况下,这可能是过度设计 -- 这正是我的想法,这可能就是作者刚刚说“去死!让它泄漏”的原因.我添加了您使用unique_ptr 的想法。感谢您的信息!
    • _ 开头的标识符由实现保留在全局命名空间中。此外,您可以重命名 window 并删除 on_active() 中的本地 window,这不会添加任何有用的东西。您只需检查if (the_unique_ptr),因为如果已设置,它也已添加,仅添加一次,并且处于活动状态。
    • 谢谢大家。也学到了一些关于 C++14 的新知识:)
    【解决方案2】:

    查看 GTKMM 文档中关于 managed widgets 的部分。您应该使用Gtk::make_managed 的一些变体:

    if (!window) {
        window = Gtk::make_managed<HelloWindow>();
        window->set_application(app);
        app->add_window(*window);
    }
    

    这样,窗口的生命周期将由应用程序管理。

    【讨论】:

    • 我测试过了。构建并运行良好。但是,在运行它时,我得到了这个错误语句尝试在 Gtk::Window 上调用 Gtk::manage(),但是 Gtk::Window 没有父容器来管理它的生命周期。。阅读托管小部件文档,我认为 Gtk::Window 类不能用 make_managed 实例化,因为它是根容器本身而不是另一个容器的子容器。
    • 嗯,这令人失望。应用程序确实应该能够管理窗口。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-13
    • 2021-09-24
    • 2023-03-30
    • 2022-01-23
    • 2023-02-10
    相关资源
    最近更新 更多