Конструктор std :: string портит указатель - PullRequest
3 голосов
/ 15 марта 2010

У меня есть класс Entity, который содержит 3 указателя: m_rigidBody, m_entity и m_parent. Где-то в Entity :: setModel (std :: string model) происходит сбой. Видимо, это вызвано плохими данными в m_entity. Странно то, что я обнулен в конструкторе и с тех пор не трогал. Я отладил его и установил на него точку наблюдения, и выяснилось, что член m_entity изменяется в конструкторе для std :: string, вызываемой при преобразовании const char * в std :: string для вызова setModel. Я работаю на Mac, если это помогает (кажется, я помню некоторые проблемы с std :: string на Mac). Есть идеи о том, что происходит?

РЕДАКТИРОВАТЬ: Вот код для GEntity:

GEntity::GEntity(GWorld* world, unsigned long int idNum) {
    GEntity(world, idNum, btTransform::getIdentity());
}

GEntity::GEntity(GWorld* world, unsigned long int idNum, btTransform trans) : m_id(idNum), m_trans(trans), m_world(world) {
    // Init unused properties
    m_rigidBody = NULL;
    m_entity = NULL; // I'm setting it here
    m_parent = NULL;

    // Find internal object name
    std::ostringstream ss;
    ss << "Entity" << idNum << "InWorld" << world;
    m_name = ss.str();

    // Create a scene node
    m_sceneNode = m_world->m_sceneMgr->getRootSceneNode()->createChildSceneNode(m_name+"Node");

    // Initialize the SceneNode's transformation
    m_sceneNode->setPosition(bv3toOv3(m_trans.getOrigin()));
    m_sceneNode->setOrientation(bqToOq(m_trans.getRotation()));
}

void GEntity::setModel(std::string model) {
    m_model = model;

    // Delete entity on model change
    if(m_entity != NULL) { // And by the time this line comes around, it's corrupt
            m_world->m_sceneMgr->destroyEntity(m_entity);
            m_entity = NULL;
    }

    // Create new entity with given model
    m_entity = m_world->m_sceneMgr->createEntity(m_name+"Ent", model);

    // Apply a new rigid body if needed
    if(m_rigidBody != NULL) {
            initPhysics();
    }
}
void GEntity::initPhysics() {
    deinitPhysics();
}

void GEntity::deinitPhysics() {
    if(m_rigidBody != NULL) {
        m_world->m_dynWorld->removeRigidBody(m_rigidBody);
        delete m_rigidBody;
        m_rigidBody = NULL;
    }
}

А вот определение GEntity:

class GEntity : public btMotionState {
public:
    GEntity(GWorld* world, unsigned long int idNum);
    GEntity(GWorld* world, unsigned long int idNum, btTransform trans);
    void setModel(std::string modelName);
    void initPhysics();
    void deinitPhysics();
    void getWorldTransform(btTransform& worldTrans) const;
    void setWorldTransform(const btTransform &trans);
    void parent(GEntity* parent);
protected:
    unsigned long int m_id;

    // Physics representation
    btTransform m_trans;
    btRigidBody* m_rigidBody;

    // Graphics representation
    Ogre::SceneNode* m_sceneNode;
    Ogre::Entity* m_entity;

    // Engine representation
    GWorld* m_world;
    GEntity* m_parent;
    std::string m_name;
    std::string m_model; // Used to find physics collision mesh
};

А вот код, вызывающий setModel:

// Setup game world
GWorld* world = new GWorld(win);
GEntity* ent = world->createEntity();
ent->setModel(std::string("Cube.mesh"));

Ответы [ 6 ]

5 голосов
/ 15 марта 2010

Ваша проблема в том, что эта строка создает безымянный временный GEntity внутри тела конструктора для другого GEntity. Временное затем отбрасывается, как только инструкция завершается, и дальнейшая инициализация невременного GEntity не выполняется.

GEntity(world, idNum, btTransform::getIdentity());

Если вы хотите разделить некоторый код инициализации между вашими двумя конструкторами, вы должны создать функцию-член, которая выполняет требуемые действия, и вызвать эту функцию из обоих конструкторов. C ++ (в настоящее время) не позволяет делегировать инициализацию от одного конструктора другому конструктору или вызывать два конструктора для одного и того же объекта.

2 голосов
/ 15 марта 2010

Мое лучшее предположение заключается в том, что проблема в GWorld :: createEntity . Если вы создаете локальный GEntity в стеке и возвращаете указатель на него, вы увидите нечто похожее на то, что вы описываете, поскольку GEntity уничтожается, когда GWorld :: createEntity возвращает, и память повторно используется для временной строки, созданной для передачи setModel

Редактировать

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

1 голос
/ 04 мая 2010

Одно решение, которое я нашел, - это использование string.resize(n), которое изменит размер функции.Однако я не знаю, почему это работает, и я чувствую, что моя проблема связана с моим кодом, поскольку std::string является частью стандартной библиотеки C ++.

0 голосов
/ 15 марта 2010

Попробуйте

GEntity::GEntity(GWorld* world, unsigned long int idNum) : GEntity(world, idNum, btTransform::getIdentity() {}

0 голосов
/ 15 марта 2010

В C ++ нельзя вызывать конструктор из конструктора.

0 голосов
/ 15 марта 2010

Я не могу найти ответ, но могу сделать предложение, которое поможет уловить проблему:

Добавить утверждения. Множество утверждений. Каждая из этих функций действительно нуждается в некоторых утверждениях, по крайней мере, в начале. Это, безусловно, поможет вам поймать неправильные состояния рано.

И, кстати, вы должны использовать постоянную ссылку в качестве параметра вашей функции setModel ().

...