You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何实现AABBTree时std::weak_ptr<T>::lock返回空shared_ptr?

问题根因

你遇到的lock()返回空的核心原因是刚创建的子节点对象在AddChild函数执行结束后就被立即销毁了:

  • 你在AddChild函数中用std::make_shared创建的子节点强引用child是函数局部变量,函数执行完后这个局部变量就会被销毁
  • 你的子节点容器m_Children存储的是std::weak_ptr类型,属于弱引用,不会增加对象的引用计数
  • 此时子节点的引用计数会从1降到0,对应的内存被直接释放,后续你通过weak_ptr::lock()自然无法获取到有效对象

设计修正建议

你的循环引用规避方案搞反了所有权关系,这才是导致问题的本质原因:
正常树结构的所有权归父节点,为了避免父子互相持有强引用导致的内存泄漏,正确的成员设计应该是:

  • 父节点持有子节点的强引用:将子节点容器改为std::vector<std::shared_ptr<AABBTreeNode>>,保证父节点存活时子节点不会被意外释放
  • 子节点持有父节点的弱引用:将父节点成员改为std::weak_ptr<AABBTreeNode>,子节点需要访问父节点时再调用lock()获取临时强引用即可

调整后的代码改动如下:

1. 调整成员变量类型

class AABBTreeNode {
    // 其他成员省略
private:
    std::weak_ptr<AABBTreeNode> m_Parent; // 父节点存弱引用
    std::vector<std::shared_ptr<AABBTreeNode>> m_Children; // 子节点存强引用
};

2. 构造函数适配

构造函数接收父节点的std::shared_ptr后,赋值给m_Parent这个弱引用成员即可。

3. 业务代码调整

AddChild函数不需要改动核心逻辑,直接把创建的子节点强引用存入容器即可:

void AABBTreeNode::AddChild(std::shared_ptr<open3d::geometry::AxisAlignedBoundingBox> partitionBound)
{
    auto child = std::make_shared<AABBTreeNode>(shared_from_this(), m_Mesh, partitionBound);
    m_Children.push_back(child);
}

AddTriangles函数不需要再调用lock(),直接使用容器里的强引用即可:

void AABBTreeNode::AddTriangles(std::vector<Eigen::Vector3d>& centers)
{
    auto center = m_Bbox->GetCenter();
    for (auto& boundPoint : m_Bbox->GetBoxPoints())
    {
        // 此处为计算最多8个子节点的minBound和maxBound的代码
        auto adjustedPartitionBound = std::make_shared<open3d::geometry::AxisAlignedBoundingBox>(minBound, maxBound);
        AddChild(adjustedPartitionBound);
        auto child = m_Children.back(); 
        // 不需要判空,只要make_shared成功就一定有效
        child->AddTriangles(partitionCenters);
    }
}

这个设计既规避了循环引用问题,也不会出现子节点被意外释放的情况。

内容的提问来源于stack exchange,提问作者Roland Deschain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 01:00:03