Open3D C++系列教程(三)关于程序异常退出的探讨

Open3D C++系列教程(三)关于程序异常退出的探讨

前置

Open3D C++系列教程 (一)环境搭建
Open3D C++系列教程 (二)第一个GUI窗口


1. 发现问题

如果你真的执行了教程(二)中的代码,细心的你可能会发现程序在最后异常退出了。
在这里插入图片描述

使用Release版o3d并生成RelWithDebInfo或使用Debug版o3d生成Debug进行调试,会发现如下的报错。
在这里插入图片描述

简单来说,就是程序最后死在了智能指针的析构上。

如果你继续往下探究,会发现在析构函数中应该是访问了已经被释放的对象。
在这里插入图片描述

2. 解决问题

2.1 方法一:将对窗口和场景所有的操作都放到一个作用域内(即一对花括号内)

注意这个地方我们将创建窗口和添加几何体的全部代码都放在一个花括号内,所有的shared_ptr在被添加到窗口后,在离开作用域时会被释放,从而确保所有的shared_ptr不会活到最后,从而可以避免程序的异常退出。

	// ----------------------------------------------------
    // ----------------------创建可视化窗口-----------------
    // ----------------------------------------------------
    {
        auto win = std::make_shared<gui::Window>("Open3D", 1920 / 2, 1080 / 2);

        // 创建场景
        auto main_scene = std::make_shared<gui::SceneWidget>();
        main_scene->SetScene(std::make_shared<rendering::Open3DScene>(win->GetRenderer()));

        // 添加场景到窗口
        win->AddChild(main_scene);

        // 添加窗口到Application
        instance.AddWindow(std::move(win));

        // ----------------------------------------------------
        // ----------------------添加几何体数据-----------------
        // ----------------------------------------------------
        for (int i = 0; i < 10; ++i)
        {
            auto mesh = TriangleMesh::CreateSphere(1.0, 4);
            mesh->PaintUniformColor(rgb(rand() % 255, rand() % 255, rand() % 255));
            mesh->Translate({rand() % 20 - 10.0, rand() % 20 - 10.0, rand() % 10 - 5.0});
            main_scene->GetScene()->AddGeometry(
                "mesh_" + std::to_string(i),  // geometry name
                mesh.get(),                   // geometry
                rendering::MaterialRecord()); // material
        }

        // 设置相机
        auto bounding_box = main_scene->GetScene()->GetBoundingBox();
        main_scene->SetupCamera(60, bounding_box, bounding_box.GetCenter().cast<float>());
    }

    instance.Run();

2.2 方法二:使用weak_ptr

weak_ptr并不持有数据,不会使shared_ptr的引用计数+1。我们为窗口需要的控件创建一个weak_ptr,所有控件的shared_ptr任然需要创建在作用域内,并在作用域内赋值给对应的weak_ptr。这样仅需将窗口的创建代码放在作用域内,而将其他的几何数据处理和添加的部分代码放在作用域外,通过weak_ptr.lock()来访问窗口控件的shared_ptr

	std::weak_ptr<gui::Window> weak_win;
    std::weak_ptr<gui::SceneWidget> weak_main_scene;
    {
        auto win = std::make_shared<gui::Window>("Open3D", 1920 / 2, 1080 / 2);
        weak_win = win;

        // 创建场景
        auto main_scene_ = std::make_shared<gui::SceneWidget>();
        main_scene_->SetScene(std::make_shared<rendering::Open3DScene>(win->GetRenderer()));
        weak_main_scene = main_scene_;

        // 添加场景到窗口
        win->AddChild(main_scene_);

        // 添加窗口到Application
        instance.AddWindow(std::move(win));
    }

    // ----------------------------------------------------
    // ----------------------添加几何体数据-----------------
    // ----------------------------------------------------
    for (int i = 0; i < 10; ++i)
    {
        auto mesh = TriangleMesh::CreateSphere(1.0, 4);
        mesh->PaintUniformColor(rgb(rand() % 255, rand() % 255, rand() % 255));
        mesh->Translate({rand() % 20 - 10.0, rand() % 20 - 10.0, rand() % 10 - 5.0});
        weak_main_scene.lock()->GetScene()->AddGeometry(
            "mesh_" + std::to_string(i),  // geometry name
            mesh.get(),                   // geometry
            rendering::MaterialRecord()); // material
    }

    // 设置相机
    auto bounding_box = weak_main_scene.lock()->GetScene()->GetBoundingBox();
    weak_main_scene.lock()->SetupCamera(60, bounding_box, bounding_box.GetCenter().cast<float>());

    instance.Run();

3. 运行结果

通过上面的修改,程序就应该能够正确退出了。
在这里插入图片描述

完整代码下载

如果不想抄代码,或者想要获取直接获取源代码文件,可以通过链接下载。那么代价是什么呢?

注:程序退出方式

在之后的代码中,你可能会发现使用ESC时程序会异常退出,使用窗口右上角的X又能够正确退出,相当的诡异!


后续

Open3D C++系列教程(四)动画 Tick事件

  • 19
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吉拉尔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值