2012-01-19 15 views
5

Được rồi, vì vậy tôi hiện đang làm việc trên một trò chơi và gặp sự cố về bộ nhớ sau khi tái cấu trúc một số mã ngay hôm nay.C++, tại sao tôi nhận được vi phạm quyền truy cập sau khi sửa đổi các đối tượng mới được phân bổ?

Nó sử dụng thiết kế dựa trên thành phần và tôi đã sửa đổi cách các thành phần được phân bổ và truyền cho các thực thể. Ban đầu một số thành phần được phân bổ như các biến thành viên trong các thực thể nhưng bây giờ tôi muốn chúng được phân bổ ở nơi khác và được truyền cho thực thể thông qua con trỏ.

Bạn có thể xem cách triển khai thực hiện điều này bên dưới bằng mã mẫu từ dự án của tôi. Tôi chủ yếu lặp qua tất cả các thực thể và phân bổ các thành phần cho chúng. Vấn đề là tôi đánh một vi phạm truy cập ở dòng đầu tiên của "bắt đầu" các "instanceObject" trên lặp thứ 6 và không có ý tưởng tại sao. Sử dụng trình gỡ lỗi, nó không giống như bất kỳ biến nào trỏ đến một địa chỉ không hợp lệ.

Đây là những gì tôi đang làm để tạo các thực thể và thành phần.

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 
} 

Và đây là mã liên quan từ thành phần.

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; 
} 

Bất kỳ ý tưởng nào về nguyên nhân gây ra hành vi này và cách khắc phục sự cố?

+1

Có một thứ không có trong mã có thể gây ra vấn đề, hàm tạo XMLoadFloat3 (hoặc nó là hàm?) Lấy XMFLOAT3 * (nó không lưu con trỏ đó, phải không?) –

+1

Bản sao constructor của 'InstanceObject' giống như hàm tạo bởi trình biên dịch. Bạn chỉ có thể xóa nó và bạn sẽ có được hành vi tương tự. –

+0

Tôi không hiểu tại sao nó lại xảy ra. Nó tải một mảng của 3 nổi vào một XMVECTOR đó là một kiểu dữ liệu đặc biệt mà sử dụng một đăng ký SIMD hoặc một cái gì đó. (http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.loading.xmloadfloat3%28v=vs.85%29.aspx) – KlashnikovKid

Trả lời

7

Tôi tin rằng vấn đề là các XMVECTOR trong lớp InstanceObject của bạn cần phải được sắp xếp 16 byte, và các nhà điều hành mới giành' t đảm bảo điều này cho bạn. Bạn có thể thêm một kiểm tra nhanh vào mã của bạn để xác nhận - kiểm tra xem con trỏ InstanceObject có phải là & 0xF không khác trong lần lặp mà nó bị treo.

Nếu đúng như vậy, bạn có thể viết trình phân bổ tùy chỉnh đảm bảo căn chỉnh đúng và sử dụng vị trí mới.

Có vẻ như đây là vấn đề khá phổ biến với XMVECTOR khi được sử dụng làm thành viên (đây là một số hiện có Connect bug report về vấn đề này, có một vài trang web nếu bạn tìm kiếm).

Nếu bạn chỉ muốn sửa chữa nó một cách nhanh chóng để cho bạn tiếp tục với những thứ khác, bạn có thể thêm một nhà điều hành tĩnh mới và xóa để khai lớp học của bạn thực hiện một cái gì đó giống như đoạn mã sau:

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); 
} 

Nếu InstanceObject chia sẻ một đời sống chung, bạn có thể thay thế việc sử dụng _aligned_malloc bằng trình phân bổ đấu trường được căn chỉnh của riêng bạn và làm cho số delete không có hiệu quả để cải thiện hiệu quả.

+0

'new' được cho là sẽ trả về bộ nhớ phù hợp cho đối tượng, nhưng có lẽ trình biên dịch không xử lý các loại SSE đúng theo cách này. Đây không phải là lần đầu tiên. –

+0

Cho đến nay câu trả lời của bạn có vẻ đúng. Sự lặp lại "xấu" không nhận được một con trỏ liên kết 16 byte. Sẽ mất một break từ nhìn chằm chằm vào điều này cả ngày và sau đó tôi sẽ kiểm tra một phân bổ tùy chỉnh. Tôi có thể khai báo các biến XMVECTOR thành viên bằng macro __declspec (align (16)) không? Tôi đã không bao giờ cần thiết hoặc viết một phân bổ tùy chỉnh trước. – KlashnikovKid

+1

Có! Bạn là một người tiết kiệm cuộc sống! Điều đó đã làm các trick. Cảm ơn bạn. – KlashnikovKid

0

Dường như cấu trúc XMFLOAT3 của bạn đang được cấp phát trên ngăn xếp chứ không phải trên heap. Họ sẽ bị làm sạch khi các biến của họ vượt quá phạm vi.

Cố gắng bố trí cấu trúc của bạn trên heap thay vì:

XMFLOAT3* _position = new XMFLOAT3; 
+0

Tôi không nghĩ điều này sẽ tạo nên sự khác biệt. XMFLOAT3s ngay lập tức được tải vào XMVECTORs. Trừ khi có một tác dụng phụ chức năng tôi không biết khi tải XMFLOAT. – KlashnikovKid

4

Bạn đang dùng địa chỉ của temporaries! Điều đó thậm chí không được phép!

// 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 
    ); 

Tôi khuyên bạn nên bật các mức cảnh báo trên cài đặt trình biên dịch của mình và cho phép nhiều chuẩn nhất có thể. Mọi thứ trở nên dễ dàng hơn nhiều khi trình biên dịch của bạn cho bạn biết bạn đang làm gì sai.

Là một giải pháp, bạn có thể thử cách đơn giản thông qua các đối tượng theo giá trị:

_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

Sẽ không đi qua 'XMFLOAT3 const &' hiệu quả hơn? – lapk

+0

@AzzA: có thể, có thể không. Lưu ý rằng hàm sẽ lưu trữ nó trong lớp. Tôi không dám dự đoán làm thế nào một trình biên dịch không được tiết lộ sẽ tối ưu hóa điều này. –

+0

Tôi khá chắc chắn đây không phải là vấn đề. Tôi đã luôn sử dụng phương pháp này khi tải XMVECTOR. Miễn là XMFLOAT3 là nguyên vẹn trên stack khi nó được nạp nó là tốt. Điều đó đang được nói rằng tôi cố gắng đi qua giá trị mà không có may mắn. – KlashnikovKid

Các vấn đề liên quan