Неправильно уничтожение класса btKinematicCharacterController

При использовании библиотеки Bullet Physics я создаю класс btKinematicCharacterController. И у меня всё идёт хорошо до тех пор, пока я не выхожу из приложение. Во время очистки динамически выделенной памяти у меня появляется ошибка: "fish: Job 1, './some_app' terminated by signal SIGSEGV (Address boundary error)". Но стоит мне удалить создание Character из исходно кода, как ошибка исчезает. Вот код удаления Character:

world->removeAction(controller);
btCollisionShape* shape = controller->getGhostObject()->getCollisionShape();
btPairCachingGhostObject* ghost_body = controller->getGhostObject();

delete controller;
delete ghost_body;
delete shape;

Вот код удаления мира:

void GTEngine::Physics::service_info::WorldData::del()
{
    for (size_t i = 0; i < Constrains.size(); i++)
        Constrains[i]->del(world);
    Constrains = {};

    for (size_t i = 0; i < RigidBodies.size(); i++)
        RigidBodies[i]->del(world);
    RigidBodies = {};

    for (size_t i = 0; i < Characters.size(); i++)
        Characters[i]->del(world);
    Characters = {};

    delete dispatcher;
    delete collisionConfig;
    delete solver;
    delete broadphase;
    delete world;
}

Я уверен что объекты создаются верно, так как при создани ошибок нет. А они сами работают (к ним можно приминить силу, реагируют друг на друга)

UPD1: Я создаю character с помощью данного кода:

    worldData->broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
    btPairCachingGhostObject* ghost_body = new btPairCachingGhostObject();
    
    btTransform t;
    t.setIdentity();
    t.setOrigin(pos);

    ghost_body->setWorldTransform(t);

    btCapsuleShape* shape = new btCapsuleShapeX(shape_size.x, shape_size.y);
    ghost_body->setCollisionShape(shape);
    ghost_body->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);

    controller = new btKinematicCharacterController(ghost_body, shape, 0.1);
    controller->setGravity(worldData->world->getGravity());

    worldData->world->addCollisionObject(ghost_body, btBroadphaseProxy::CharacterFilter,
                                         btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DebrisFilter);
    worldData->world->addAction(controller);

UPD2: Ошибка возникает при удалении мира:

delete world;

Я думаю что в мире сохраняются какие то ссылки, но я не уверен в этом.


Ответы (2 шт):

Автор решения: citn

Ответ затаился в вопросе: Когда вызываете delete controller - вы, собственно, освобождаете память, занимаемую controller и все связанные с ним объекты становятся недоступными, поэтому, когда вызывается controller->getGhostObject() - происходит неопределенное поведение, т.к. controller уже был удален. Попробуйте просто поменять порядок удаления, ну и как рекомендация - лучше добавлять проверку на nullptr перед удалением.

void deleteCharacter(btKinematicCharacterController* controller) {
    if (controller) {
        btPairCachingGhostObject* ghost_body = controller->getGhostObject();
        if (ghost_body) {
            btCollisionShape* shape = ghost_body->getCollisionShape();
            world->removeAction(controller);
            delete shape;
            delete ghost_body;
        }
        delete controller;
    }
}

А еще можно посмотреть в сторону умных указателей - unique_ptr и shared_ptr.

Если ошибка осталась, то либо добавь деталей к вопросу(а то, смотря на код, довольно тяжело представить, что у тебя там написано), пройдись отладчиком

→ Ссылка
Автор решения: jdoseIOO

Проблема была в том, что я не удалял объект коллизии и он оставался в мире. Вот мой не правильный код:

world->removeAction(controller);
btCollisionShape* shape = controller->getGhostObject()->getCollisionShape();
btPairCachingGhostObject* ghost_body = controller->getGhostObject();

delete controller;
delete ghost_body;
delete shape;

И вот как это нужно делать (правильный код и спасибо cith за совет):

{
    if (isDelete) return; else isDelete = true;
    if (!controller) return;
    
    btPairCachingGhostObject* ghost_body = controller->getGhostObject();
    if (ghost_body)
    {
        btCollisionShape* shape = ghost_body->getCollisionShape();
        world->removeCollisionObject(ghost_body);
        world->removeAction(controller);
        delete shape;
        delete ghost_body;
    }
    delete controller;
    controller = nullptr;
}
→ Ссылка