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

Box2D封装为RigidBody类后与std::vector搭配时erase操作行为异常

问题根源

你遇到的异常行为是C++「三/五法则」的典型触发场景,核心原因是你的RigidBody类只实现了拷贝构造函数和析构函数,没有实现拷贝赋值运算符,编译器自动生成的默认拷贝赋值是纯浅拷贝,直接复制m_body、m_fixture两个指针的值,完全没有处理底层Box2D物理对象的生命周期,和std::vector的erase逻辑适配就出了问题:
std::vector执行erase操作时的逻辑是:将被删除位置之后的所有元素,依次向前拷贝赋值覆盖前一个位置的元素,最后销毁vector末尾的冗余元素。举个例子:假设你的vector有[obj0, obj1, obj2, obj3]四个元素,调用erase(begin())删除obj0时,实际执行步骤是:

  1. 用obj1赋值给obj0的内存位置
  2. 用obj2赋值给obj1的内存位置
  3. 用obj3赋值给obj2的内存位置
  4. 调用obj3的析构函数,删除末尾元素
    默认浅拷贝赋值会直接把obj1的m_body指针覆盖给原来的obj0,obj0原本持有的Box2D Body直接泄漏,最后析构obj3的时候销毁了obj3对应的物理体,所以你看起来就像「删除第一个元素,实际消失的是最后一个」。
    第二次执行erase操作时,vector末尾元素的m_body已经是被销毁过的野指针,析构时调用Runtime::PhysicsWorld.DestroyBody访问野指针自然触发崩溃。

解决方案

你可以根据自己的使用场景选任意一种方案修复:

方案1:禁止值语义(最推荐,性能最优)

Box2D的Body本身就不应该随意拷贝,直接禁用RigidBody的拷贝构造和拷贝赋值,vector中存储智能指针即可:

class RigidBody {
public:
    // 禁用拷贝
    RigidBody(const RigidBody&) = delete;
    RigidBody& operator=(const RigidBody&) = delete;
    // 实现移动语义,支持vector内部移动元素
    RigidBody(RigidBody&& other) noexcept {
        m_body = other.m_body;
        m_fixture = other.m_fixture;
        other.m_body = nullptr; // 置空原对象指针,避免析构重复销毁
        other.m_fixture = nullptr;
    }
    RigidBody& operator=(RigidBody&& other) noexcept {
        if (this != &other) {
            // 先销毁自己当前持有的资源
            if (m_body) Runtime::PhysicsWorld.DestroyBody(m_body);
            // 转移所有权
            m_body = other.m_body;
            m_fixture = other.m_fixture;
            other.m_body = nullptr;
            other.m_fixture = nullptr;
        }
        return *this;
    }
    // 析构函数加判空
    ~RigidBody() {
        if (m_body) Runtime::PhysicsWorld.DestroyBody(m_body);
    }
    // 其他原有逻辑...
};

// 存储用智能指针避免拷贝
std::vector<std::unique_ptr<hv::RigidBody>> m_Bodies;

方案2:补全拷贝赋值运算符(如果确实需要值拷贝语义)

如果你确实需要复制RigidBody时生成完全独立的新物理体,就按照拷贝构造的逻辑实现拷贝赋值运算符:

RigidBody& RigidBody::operator=(const RigidBody& other) {
    if (this == &other) return *this;
    // 先销毁当前持有的物理资源
    if (m_body) Runtime::PhysicsWorld.DestroyBody(m_body);
    // 复用拷贝构造逻辑创建新的物理体
    m_fixture = other.m_fixture;
    b2BodyDef bodyDef;
    bodyDef.position = other.m_body->GetPosition();
    bodyDef.type = other.m_body->GetType();
    m_body = Runtime::PhysicsWorld.CreateBody(&bodyDef);
    b2FixtureDef fixtureDef;
    fixtureDef.shape                = m_fixture->GetShape();
    fixtureDef.density              = m_fixture->GetDensity();
    fixtureDef.friction             = m_fixture->GetFriction();
    fixtureDef.restitution          = m_fixture->GetRestitution();
    fixtureDef.restitutionThreshold = m_fixture->GetRestitutionThreshold();
    m_fixture = m_body->CreateFixture(&fixtureDef);
    return *this;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 05:24:05