C ++,为什么我在修改新分配的对象后会出现访问冲突?

时间:2012-01-19 20:59:58

标签: c++ memory-management

好吧,所以我正在开发一款游戏,并在今天重构了一些代码后遇到了内存问题。

它使用基于组件的设计,我正在修改组件的分配和传递给实体的方式。最初一些组件被分配为实体中的成员变量,但现在我想将它们分配到别处并通过指针传递给实体。

您可以使用我项目中的示例代码了解我如何实现此功能。我基本上遍历所有实体并为它们分配组件。问题是我在第6次迭代“启动”“instanceObject”的第一行遇到了访问冲突,并且不明白为什么。使用调试器,它看起来不像任何变量指向无效的地址。

以下是我正在创建的实体和组件。

for (unsigned int i = 0; i < 512; ++i) {
    InstanceObject* _pInstanceObject = new InstanceObject;

    // Initialize temporary variables
    XMFLOAT3 _position, _rotation;
    float _angle = (i / 512.0f) * (2.0f * XM_PI),
          _scale = (float)pResourceManager->numberGenerator.GetInt(50, 5);

    _position.x = 100000.0f * cos(_angle) + pResourceManager->numberGenerator.GetInt(50000, -25000);
    _position.y =(float) pResourceManager->numberGenerator.GetInt(50000, -25000);
    _position.z = 100000.0f * sin(_angle) + pResourceManager->numberGenerator.GetInt(50000, -25000);

    _rotation.x = (XM_PI * 2) * (pResourceManager->numberGenerator.GetInt(100, 0) / 100.0f);
    _rotation.y = (XM_PI * 2) * (pResourceManager->numberGenerator.GetInt(100, 0) / 100.0f);
    _rotation.z = (XM_PI * 2) * (pResourceManager->numberGenerator.GetInt(100, 0) / 100.0f);

    // Set component's state using the temporary variables.
    _pInstanceObject->StartUp(&_position,
        &_rotation,
        &XMFLOAT3(_scale, _scale, _scale),
        &XMFLOAT3(0.0f, 0.0f, 1.0f),
        &XMFLOAT3(1.0f, 0.0f, 0.0f),
        &XMFLOAT3(0.0f, 1.0f, 0.0f)
        );

    // Hand pointer of the component to entity.
    // Entity will handle deallocating component
}

以下是该组件的相关代码。

class InstanceObject {
private:
    XMVECTOR anteriorAxis,
         lateralAxis,
         normalAxis,
         position,
         rotationQuaternion,
         scale;

    XMMATRIX translationMatrix,
         rotationMatrix,
         scaleMatrix;
    void SetAnteriorAxis(const XMFLOAT3 *_anteriorAxis) { anteriorAxis = XMLoadFloat3(_anteriorAxis); }
    void SetLateralAxis(const XMFLOAT3 *_lateralAxis)   { lateralAxis = XMLoadFloat3(_lateralAxis); }
    void SetNormalAxis(const XMFLOAT3 *_normalAxis)     { normalAxis = XMLoadFloat3(_normalAxis); }
public:
    InstanceObject(void)  { }
    InstanceObject(const InstanceObject& _object) : anteriorAxis(_object.anteriorAxis), lateralAxis(_object.lateralAxis),
        normalAxis(_object.normalAxis), position(_object.position), rotationQuaternion(_object.rotationQuaternion), scale(_object.scale),
        translationMatrix(_object.translationMatrix), rotationMatrix(_object.rotationMatrix), scaleMatrix(_object.scaleMatrix) {}
    ~InstanceObject(void) { }

    bool StartUp(const XMFLOAT3 *_position, const XMFLOAT3 *_rotation, const XMFLOAT3 *_scale,
        const XMFLOAT3 *_lookAxis, const XMFLOAT3 *_strafeAxis, const XMFLOAT3 *_upAxis);

    void SetPosition(const XMFLOAT3* _position) { position = XMLoadFloat3(_position); }
    void SetRotationQuaternion(const XMFLOAT3 *_rotation) { rotationQuaternion = XMQuaternionRotationRollPitchYaw(_rotation->x, _rotation->y, _rotation->z); }
    void SetScale(const XMFLOAT3 *_scale) { scale = XMLoadFloat3(_scale); }
}

bool InstanceObject::StartUp(const XMFLOAT3 *_position, const  XMFLOAT3 *_rotation, const XMFLOAT3 *_scale,
        const XMFLOAT3 *_lookAxis, const XMFLOAT3 *_strafeAxis, const XMFLOAT3 *_upAxis) {
    SetPosition(_position);
    SetRotationQuaternion(_rotation);
    SetScale(_scale);   
    SetAnteriorAxis(_lookAxis);
    SetLateralAxis(_strafeAxis);
    SetNormalAxis(_upAxis);

    return true;
}

知道可能导致此行为的原因以及我该如何解决?

3 个答案:

答案 0 :(得分:7)

我认为问题是InstanceObject类中的XMVECTOR需要16字节对齐,而new运算符不能保证这一点。您可以在代码中添加快速检查以确认 - 检查InstanceObject指针&amp; 0xF在崩溃的迭代中不为零。

如果是这种情况,您可以编写一个自定义分配器,以保证正确对齐并使用新的位置。

当用作成员时,XMVECTOR似乎是一个相当普遍的问题(在这个问题上这是一个现有的Connect bug report,如果你搜索,有一些网页。)

如果你只是想快速修复它以让你继续处理其他事情,你可以添加一个静态运算符new并删除你的类声明实现类似下面的代码片段:

void* InstanceObject::operator new( size_t size )
{
    // _aligned_malloc is a Microsoft specific method (include malloc.h) but its
    // straightforward to implement if you want to be portable by over-allocating
    // and adjusting the address
    void *result = _aligned_malloc( size, 16 );
    if( result )
        return result;

    throw std::bad_alloc(); 
}

void InstanceObject::operator delete( void* p )
{
    if( p ) _aligned_free(p);
}

如果InstanceObject共享一个共同的生命周期,您可以将_aligned_malloc替换为您自己的对齐竞技场分配器,并使delete成为无操作以提高效率。

答案 1 :(得分:4)

你正在拿着临时的地址!甚至不允许这样做!

// Set component's state using the temporary variables.
_pInstanceObject->StartUp(&_position,
    &_rotation,
    &XMFLOAT3(_scale, _scale, _scale), // not valid
    &XMFLOAT3(0.0f, 0.0f, 1.0f), // not valid
    &XMFLOAT3(1.0f, 0.0f, 0.0f), // not valid
    &XMFLOAT3(0.0f, 1.0f, 0.0f) // not valid
    );

我建议您在编译器设置上调高警告级别,并尽可能提高标准一致性。当你的编译器告诉你你做错了什么时,事情变得容易了。

作为解决方案,您可以尝试按值传递对象:

_pInstanceObject->StartUp(_position,
    _rotation,
    XMFLOAT3(_scale, _scale, _scale),
    XMFLOAT3(0.0f, 0.0f, 1.0f),
    XMFLOAT3(1.0f, 0.0f, 0.0f),
    XMFLOAT3(0.0f, 1.0f, 0.0f)
    );


bool StartUp(XMFLOAT3 _position, XMFLOAT3 _rotation, XMFLOAT3 _scale,
    XMFLOAT3 _lookAxis, XMFLOAT3 _strafeAxis, XMFLOAT3 _upAxis);

答案 2 :(得分:0)

看起来您的XMFLOAT3结构正在堆栈上分配,而不是在堆上。当变量超出范围时,它们会被清理干净。

尝试在堆上分配您的结构:

XMFLOAT3* _position = new XMFLOAT3;