【问题标题】:Access violation and strange behavior of Visual StudioVisual Studio 的访问冲突和奇怪行为
【发布时间】:2014-03-16 13:34:44
【问题描述】:

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

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 配置下构建我的解决方案。相机构造函数一直落在“未处理的异常:访问违规读取位置...”上在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是camera类的全局指针,别这么看我,这在VS下工作了一段时间。

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

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

我在调试模式下有工作解决方案,我决定在发布下禁用优化,它在 VS 下工作,而不是在我启动 .exe 时工作。我已经尝试了所有方法,但我不知道如何处理这种情况。我再次检查了,我没有错误的指针。我读过一些关于内存泄漏的文章,但即使我在使用后尝试 delete 或 free() 内存,它还是会崩溃。我很绝望。

【问题讨论】:

  • 几乎可以肯定是因为 XMMATRIX 成员变量不是 16 字节对齐的。
  • 我在项目属性中有16字节结构成员对齐...

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


【解决方案1】:

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

可能的解决方案是:

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

您可能会发现这两个答案很有用:one、two

C++ 笔记(题外话):
- 切勿混合new/free、malloc/delete。你不能。
- 我们倾向于在 C++ 中避免所有这四个。更喜欢使用智能指针:std::shared_ptr、std::unique_ptr,以及它们的配套函数:std::make_shared、std::make_unique()
- 这是内存泄漏(分配给cam 的内存在分配后将永远丢失,您无法再释放它):

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

- 改为:

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

希望它以某种方式有所帮助。 编码愉快!

【讨论】:

  • 看来我终于修复了这个错误。我所做的: 1. 我已经停止使用动态分配。 2. 我已经开始使用 XMFLOAT4 和 XMFLOAT4X4 数据类型来存储值。 3.我已经摆脱了全局变量,并制作了camera* shared_ptr。我仍然使用 DirectXMath 库和 SSE 内在函数。应用程序有效。非常感谢您的回答。
猜你喜欢
  • 2015-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多