2012-01-19 35 views
5

好的,所以我目前正在研究一款遊戲,並在今天重構了一些代碼之後遇到了內存問題。C++,爲什麼在修改新分配的對象後會出現訪問衝突?

它使用基於組件的設計,並且我正在修改組件如何分配和傳遞給實體。最初一些組件被分配爲實體內的成員變量,但現在我想讓它們在別處分配並通過指針傳遞給實體。

你可以看到我是如何在我的項目中使用示例代碼實現它的。我基本上遍歷所有實體併爲它們分配組件。問題是我在第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; 
} 

任何想法可能會導致此行爲,我該如何解決它?

+1

有一件事情不在代碼中,肯定會導致問題,XMLoadFloat3的構造函數(或者它是一個函數?)需要一個XMFLOAT3 *(它不存儲該指針嗎?) –

+1

複製'InstanceObject'的構造函數就像編譯器自由生成的一樣。你可以刪除它,你會得到相同的行爲。 –

+0

我不明白爲什麼會這樣。它將3個浮點數組加載到XMVECTOR中,該XMVECTOR是使用SIMD寄存器或其他類型的特殊數據類型。 (http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.loading.xmloadfloat3%28v=vs.85%29.aspx) – KlashnikovKid

回答

7

我認爲,問題是,在你的InstanceObject類XMVECTOR需要進行16字節對齊,而新運營商獲得了」不保證爲你服務。您可以在代碼中添加快速檢查以確認 - 檢查InstanceObject指針& 0xF在其崩潰的迭代中是否爲零。

如果是這種情況,您可以編寫一個自定義分配器,以保證正確的對齊並使用新的位置。

當作爲成員使用時(在這個問題上,現有Connect bug report,如果您搜索,有幾個網頁),它似乎是XMVECTOR的一個相當常見的問題。

如果你只是想快速解決問題,讓你與其他的東西,你可以添加一個靜態的operator new和delete你的類聲明中實現類似下面的代碼片段:

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無效以提高效率。

+0

'new'應該爲對象返回正確對齊的內存,但編譯器可能不會正確地對待SSE類型。這不會是第一次。 –

+0

到目前爲止,您的答案似乎是正確的。 「壞」迭代沒有得到一個16字節的對齊指針。要整天盯着這個休息片刻,然後我會測試一個自定義分配器。我可以用__declspec(align(16))宏聲明成員XMVECTOR變量嗎?我從來沒有需要或寫過自定義分配器。 – KlashnikovKid

+1

是的!你是一個拯救生命的人!那就是訣竅。謝謝。 – KlashnikovKid

0

它看起來像你的XMFLOAT3結構被分配在堆棧上,而不是在堆上。當變量超出範圍時,他們會得到清理。

嘗試在堆中分配的結構,而不是:

XMFLOAT3* _position = new XMFLOAT3; 
+0

我不認爲這會有所作爲。 XMFLOAT3立即被加載到XMVECTOR中。除非有功能性副作用,我不知道如何加載XMFLOAT。 – KlashnikovKid

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); 
+0

不會傳遞'XMFLOAT3 const'效率更高? – lapk

+0

@AzzA:也許,也許不是。請注意,該函數將存儲在類中。我不敢預測一個未公開的編譯器如何優化這個。 –

+0

我很確定這不是問題。我一直使用這種方法來加載XMVECTOR。只要XMFLOAT3在被加載時在棧上完好無損,它就沒有問題。這就是說,我嘗試通過價值沒有運氣。 – KlashnikovKid

相關問題