std::string构造函数破坏指针。

3
我有一个实体类(Entity class),其中包含3个指针:m_rigidBody、m_entity和m_parent。在Entity::setModel(std::string model)的某个地方,程序崩溃了。显然,这是由于m_entity中存在错误数据导致的。奇怪的是,在构造函数中将其置零后,我从未再次使用过它。我进行了调试并在其上设置了监视点,结果发现在转换const char*为std::string以用于setModel调用时调用std::string的构造函数时,m_entity成员会被修改。如果有帮助的话,我正在Mac上运行(我记得在Mac上有一些关于std::string的问题)。你对发生了什么有什么想法吗?
编辑: 这是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"));

7
从 std::string 构造函数没有错误的假设开始工作。在这些论坛或谷歌中搜索“堆栈损坏”。 - Hans Passant
4
我打赌 std::string 构造函数里面没有 bug,但是你的代码有一个巨大的 bug... - stefanB
1
我认为至少需要发布调用setModel的代码中GEntity的定义;最好是一个能够演示问题的最小完整可编译程序。 - CB Bailey
1
将值打印到控制台。我已经通过艰难的方式学会了不要相信Xcode调试器(特别是对于字符串)。 - dirkgently
1
当我在GWorld::createEntity中替换了两个参数的调用时,它能正常工作。 - nonpolynomial237
显示剩余11条评论
6个回答

5

您的问题在于,这行代码在不同的 GEntity 的构造函数体内构造了一个无名临时对象。一旦语句完成并且没有对非临时 GEntity 进行进一步初始化,该临时对象将被丢弃。

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

如果你想在两个构造函数之间共享一些初始化代码,你应该创建一个成员函数来执行所需的操作,并从两个构造函数中调用此函数。C++目前不允许你将初始化委托从一个构造函数传递到另一个构造函数或在同一个对象上调用两个构造函数。


1
既然我们看到了这个构造函数,那么它似乎很明显!在C++0x发布之前,将无法调用同一类上的构造函数。 - Klaim
1
谢谢。我以为C++会有这个功能,因为我花了时间编写Objective-C代码。 - nonpolynomial237

2
我的最佳猜测是问题在于中。 如果你在堆栈上创建一个本地的并返回指向它的指针,你会看到像你描述的那样的情况,因为在返回时被销毁,并且内存被重用以用于传递给的临时字符串构造

编辑 我看到你添加了更多代码,包括的定义。看起来很好,但我仍然建议查找GEntity出现问题的方式被删除(并且内存被重用为字符串)之前调用setModel。


1
我找到的一个解决方案是使用 string.resize(n),它可以调整函数的大小。然而,我不知道为什么这样做有效,我感觉我的问题可能出在代码上,因为 std::string 是标准 C++ 库的一部分。

0

我找不到答案,但我可以提出一个建议,有助于解决问题:

添加断言。许多断言。这些函数中的每一个都需要至少在开头添加一些断言。这肯定会帮助您早期发现错误状态。

顺便说一句,你应该把一个常量引用作为setModel()函数的参数。


0
在C++中,您不能从构造函数中调用构造函数。

0

尝试

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接