访问冲突和Visual Studio的奇怪行为

时间:2014-03-16 13:34:44

标签: visual-studio-2012 memory-management memory-leaks directx directx-11

我正在DirectX11上编写测试应用程序,我有2个类“Box”和“camera”。 “Box”是一个要在屏幕上绘制的立方体,这是“相机”:

class camera 
{ 
public :
const camera operator=(const camera& fv) const
{
    return fv;
}
XMVECTOR eye;
XMVECTOR at;
XMVECTOR up;
XMVECTOR right;
XMVECTOR left;
XMVECTOR down;
float pitch; //x
float roll; //z
float yaw; //y

XMMATRIX View;
XMMATRIX Projection;
camera();
camera(XMVECTOR eye, XMVECTOR at, XMVECTOR up, float movingOffset, float radius);
void Move(XMVECTOR Offset);
void MoveCameraRight(float offset);
void Rotate(XMVECTOR offset);
void MoveCameraLeft(float offset);

void MoveCameraUp(float offset);
void MoveCameraDown(float offset);
void MoveCameraCloser(float offset);
} ;

我在Visual Studio 2012中工作,一切都很完美,直到我决定在Release config下构建我的解决方案。相机构造函数始终位于0x0附近的不同地址上的“未处理的异常:访问违规读取位置......”。我知道为什么会发生这种情况,我已经检查了我使用的所有指针,而且我完全不明白,发生了什么。这是具有WinMain函数的文件的开头:

#include <stdio.h>
#include "DIMouse.h"
#include <string>
#include <sstream>
#include <iostream>


HINSTANCE               g_hInst = nullptr;
HWND                    g_hWnd = nullptr;
HRESULT                 hr = S_OK;
D3D_DRIVER_TYPE         g_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVEL       g_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device*           g_pd3dDevice = nullptr;
ID3D11DeviceContext*    g_pImmediateContext = nullptr;
IDXGISwapChain*         g_pSwapChain = nullptr;
ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
ID3D11VertexShader*     g_pVertexShader = nullptr;
ID3D11PixelShader*      g_pPixelShader = nullptr;
ID3D11InputLayout*      g_pVertexLayout = nullptr;
ID3D11Buffer*           g_pVertexBuffer = nullptr;
ID3D11Buffer*           g_pConstantBuffer = nullptr;
ID3D11Buffer*           g_pIndexBuffer = nullptr;
XMMATRIX                g_World;                     // World matrix
XMMATRIX                g_View;           // View matrix
XMMATRIX                g_Projection;           // Projection matrix

int BOXES_COUNT = 50;
int Radius = 20;
FILE* fpsLog = NULL;
Box** boxes;
camera* cam;
FPS fps;
int calculationId = 0;

 HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow );
 HRESULT InitDevice();
 HRESULT InitGeometry();
 void parseArgs(LPWSTR  lpl);
void CleanupDevice();
LRESULT CALLBACK    WndProc( HWND, UINT, WPARAM, LPARAM );
void Render();
HRESULT InitCamera();   
void InitCubes(int boxesCount);
cDIObject DIObject;
cMouse Mouse;

 int WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,   _In_     LPWSTR lpCmdLine, _In_ int nCmdShow )
 {
//parse args
parseArgs( lpCmdLine );
UNREFERENCED_PARAMETER( hPrevInstance );
UNREFERENCED_PARAMETER( lpCmdLine );

  ....
     if (FAILED ( InitCamera()))
{
    .....

InitCamera() - 一个函数,我调用构造函数,当所有崩溃时:

HRESULT InitCamera()
{
  RECT rc;
   GetClientRect( g_hWnd, &rc );
   UINT width = rc.right - rc.left;           
   UINT height = rc.bottom - rc.top;   
   g_World = XMMatrixIdentity();

   XMVECTOR Eye = XMVectorSet( 0.0f, 0.0f, -45, 0.0f );  
   XMVECTOR At = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f );    
   XMVECTOR Up = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );    
   g_View = XMMatrixLookAtLH( Eye, At, Up );
   g_Projection = XMMatrixPerspectiveFovLH( XM_PIDIV4, width / (FLOAT)height, 0.01f,    100.0f );
cam = (camera*)malloc(sizeof(camera));
  camera * c = new camera( Eye, At, Up, 0.5, Radius );
cam = c;

cam 是一个指向相机类的全局指针,不要那样看我,这在VS下工作了一段时间。

如果我需要解析来自lpCmdLine的命令行参数,我需要分配内存,我想,原因是在..Main开头的内存分配。我使用 malloc()和数组(使用new然后删除),但即使我调用了free()并使用了delete运算符,也会发生“访问冲突”。但是,现在关注!有时它在Visual Studio下工作,当我没有尝试分配内存,并且当我刚刚启动.exe文件时没有工作。然后我决定查看没有内存分配会发生什么,它在VS和外部工作(当我启动.exe时)。但是当我从代码中删除所有内存分配以查看会发生什么时,我还在线路上获得了“访问冲突...”

   camera * c = new camera( Eye, At, Up, 0.5, Radius );

我在调试模式下有工作解决方案,我决定在Release下禁用优化,它在VS下运行比在启动.exe时不起作用。我已经尝试了一切,我不知道如何处理这个案子。我再次检查,我没有坏指针。我已经阅读了一些有关内存泄漏的内容,但即使我在使用后尝试删除 free()内存,它仍然会崩溃。我很绝望。

1 个答案:

答案 0 :(得分:2)

假设您已经检查并调试了所有可能的指针问题(我有疑问),最可能的错误是未对齐的DirectXMath。 XMVECTOR and XMMATRIX objects must be 16-byte aligned

可能的解决方案是:

  • 使用对齐分配
  • 不要使用动态分配(在堆栈上放置对象)
  • 使用XMFLOATaXMFLOATaXb(其中ab为维度)作为存储(类成员,函数参数等)并转换为{{1}和计算前的XMMATRIX(放在ctack上)
  • 禁用SSE内在函数(在包含文件之前放置#define _XM_NO_INTRINSICS_)。它将禁用对齐要求
  • 不要使用DirectXMath(还有很多其他数学库)

您可能会发现这两个答案很有用:onetwo

C ++笔记(offtopic):
  - 永远不要混用XMVECTOR / newfree / malloc。你不能。
  - 我们倾向于在C ++中避免所有这四个。更喜欢使用智能指针:deletestd::shared_ptr及其配套功能:std::unique_ptrstd::make_shared
  - 这是内存泄漏(分配给std::make_unique()的内存在分配后永远丢失,你不能再发布它了):

cam = (camera*)malloc(sizeof(camera));
camera * c = new camera( Eye, At, Up, 0.5, Radius );
cam = c;

- 改为:

std::shared_ptr<Camera> cam;
...
cam = std::make_shared<Camera>(Eye, At, Up, 0.5, Radius);
- 在C ++中被认为是邪恶的全局变量
- 在C ++中被认为是邪恶的原始指针
- 检查The Definitive C++ Book Guide and List(“最佳实践”和“中级”部分)

希望它有所帮助。 快乐的编码!