странная ошибка нарушения прав доступа

Я получаю (для меня) странную ошибку нарушения прав доступа во время выполнения. У меня есть класс GUI, который содержит необработанный указатель на экземпляр другого класса, Crosshair. Однако, когда я пытаюсь получить доступ к этому указателю, я получаю ошибку времени выполнения! Я говорю о доступе к указателю, мне даже не нужно разыменовывать его, чтобы получить ошибку.

Вот ошибка:

Unhandled exception at 0x00d4c486 in GPEngine.exe: 0xC0000005: Access violation reading location 0x00000004.

Ошибка возвращается к этой строке: int a = (int)m_pCrosshair; Которая находится в методе GUI::Draw(), указанном ниже.


РЕДАКТИРОВАТЬ:

Я нашел проблему. Это произошло в коде, который я скрывал от вас, ребята, пытаясь скрыть как можно больше ненужного кода... Проблема заключалась в следующем:

bool PsychoBots_Game::InitGame()
{
//more code...
return true;
//////GUI
    GUIOnIntialisationInfo GUIdesc;
    GUIdesc.pContentManager = m_pContentManager;
    GUIdesc.pDevice = m_pLevel->GetDevice();

    m_pGUI = new GUI(GUIdesc);
}

Чистая глупость, другими словами... Извините за это! Я не писал первую часть этого метода, поэтому я не знал о возвращаемых значениях, так как я никогда не использую его при инициализации своих собственных вещей...


Старый:

Код:

Перекрестие.h

#pragma once

#include "D3DUtil.h"

class ContentManager;
class RenderContext;

class Crosshair
{
public:
    Crosshair(ID3D10Device* pDevice, ContentManager *pContentManager);
    virtual ~Crosshair();

    void Draw(ID3D10Device* pDevice, int clientWidth, int clientHeight);

private:
    ID3D10InputLayout*          m_pVertexLayout;
    ID3D10Buffer*               m_pVertexBuffer;

    ID3D10Effect*               m_pDefaultEffect;
    ID3D10EffectTechnique*      m_pDefaultTechnique;

    ID3D10EffectMatrixVariable* m_pWVPVariable;
    ID3D10EffectShaderResourceVariable* m_pDiffuseMapVariabele;

    ID3D10ShaderResourceView *  m_pTextureRV;

private:
    //disabled
    Crosshair(const Crosshair& b);
    Crosshair& operator= (const Crosshair& b);
};

Crosshair.cpp

#include "stdafx.h"

#include "Crosshair.h"

#include "ContentManager.h"
#include "RenderContext.h"

#include "vertex.h"

Crosshair::Crosshair(ID3D10Device* pDevice, ContentManager *pContentManager)
    :m_pVertexLayout(nullptr)
    ,m_pVertexBuffer(nullptr)
    ,m_pDefaultEffect(nullptr)
    ,m_pDefaultTechnique(nullptr)
    ,m_pWVPVariable(nullptr)
    ,m_pDiffuseMapVariabele(nullptr)
    ,m_pTextureRV(nullptr)
{
//////Load Texture
    m_pTextureRV = pContentManager->GetTexture(pDevice, _T("GUI/Crosshair.png"));

//////Load Effect & Technique
    m_pDefaultEffect = pContentManager->GetEffect(pDevice,  _T("Effect/Texture2D.fx"));

    //get  technique 
    m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByIndex(0);
    if(!m_pDefaultTechnique->IsValid())
    {
        MessageBox(0,_T("Technique not valid"),_T("ERROR"),0);
        exit(-1);
    }

//////Get Effect Variables
    m_pDiffuseMapVariabele = m_pDefaultEffect->GetVariableBySemantic("DiffuseMap")->AsShaderResource();
    if(!m_pDiffuseMapVariabele->IsValid()) {
        MessageBox(0,_T("Getting EffectVariable m_pDiffuseMapVariabele Failed"),_T("ERROR"),0);
        exit(-1);
    }

    m_pWVPVariable = m_pDefaultEffect->GetVariableBySemantic("WVP")->AsMatrix();
    if(!m_pWVPVariable->IsValid()) {
        MessageBox(0,_T("Getting EffectVariable m_pWVPVariable Failed"),_T("ERROR"),0);
        exit(-1);
    }

//////Define InputLayout
    D3D10_INPUT_ELEMENT_DESC layout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }
    };
    UINT numElements = sizeof(layout)/sizeof(layout[0]);

    // Create the input layout
    D3D10_PASS_DESC PassDesc;
    // Get the pass decriptor from the effect technique
    m_pDefaultTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
    HR(pDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &m_pVertexLayout ));

//////Build Vertexbuffer
    VertexPosTex v[4];

    v[0].pos = D3DXVECTOR3(-0.5f, -0.5f, 0.0f); v[0].tex.x = 0.0f; v[0].tex.y = 1.0f;
    v[1].pos = D3DXVECTOR3(-0.5f,  0.5f, 0.0f); v[1].tex.x = 0.0f; v[1].tex.y = 0.0f;
    v[2].pos = D3DXVECTOR3( 0.5f, -0.5f, 0.0f); v[2].tex.x = 1.0f; v[2].tex.y = 1.0f;
    v[3].pos = D3DXVECTOR3( 0.5f,  0.5f, 0.0f); v[3].tex.x = 1.0f; v[3].tex.y = 0.0f;

    //fill a buffer description to copy the vertexdata into graphics memory
    D3D10_BUFFER_DESC bd = {};
    bd.Usage = D3D10_USAGE_DEFAULT;
    bd.ByteWidth = sizeof( VertexPosTex ) * sizeof(v);
    bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags = 0;
    bd.MiscFlags = 0;

    D3D10_SUBRESOURCE_DATA initData;
    initData.pSysMem = v;
    //create a ID3D10Buffer in graphics memory containing the vertex info
    HR(pDevice->CreateBuffer( &bd, &initData, &m_pVertexBuffer ));
}

Crosshair::~Crosshair()
{
    m_pVertexLayout->Release();
    m_pVertexBuffer->Release();
}

void Crosshair::Draw(ID3D10Device* pDevice, int clientWidth, int clientHeight)
{
//////Set the input layout
    pDevice->IASetInputLayout( m_pVertexLayout );

//more code...
}

GUI.h

#pragma once

#include "D3DUtil.h"

#include "GUIOnInitialisationInfo.h"
#include "GUIPerFrameInfo.h"
#include "GUIPerTickInfo.h"

#include "Crosshair.h"

class GUI
{
public:
    virtual ~GUI();
    GUI(const GUIOnIntialisationInfo& info);

    void Tick(const GUIPerTickInfo& info);
    void Draw(const GUIPerFrameInfo& info);

private:
    Crosshair* m_pCrosshair;
};

GUI.cpp

#include "stdafx.h"
#include "GUI.h"
GUI::GUI(const GUIOnIntialisationInfo& info)
    :m_pCrosshair(new Crosshair(info.pDevice, info.pContentManager))
{
}
GUI::~GUI()
{
    delete m_pCrosshair;
}
void GUI::Tick(const GUIPerTickInfo& info)
{
}
void GUI::Draw(const GUIPerFrameInfo& info)
{
    int a = (int)m_pCrosshair; 
    m_pCrosshair->Draw(info.pDevice, info.clientWidth, info.clientHeight);
}

Ошибка возвращается в эту строку: int a = (int)m_pCrosshair;

Когда я удалю эту строку: она прервется на m_pCrosshair->Draw(info.pDevice, info.clientWidth,info.clientHeight);

С ошибкой: Unhandled exception at 0x001fc49a in GPEngine.exe: 0xC0000005: Access violation reading location 0x00000004


Вот как создается экземпляр GUI в моем приложении:

class PsychoBots_Game : public D3DApp
{
//more code...
private:
    GUI* m_pGUI;
//more code...
};

(пожалуйста, не спрашивайте меня, зачем мне метод InitGame(), мы должны сделать это, чтобы наши учителя были счастливы [смеется])

bool PsychoBots_Game::InitGame()
{
//////GUI
    GUIOnIntialisationInfo GUIdesc;
    GUIdesc.pContentManager = m_pContentManager;
    GUIdesc.pDevice = m_pLevel->GetDevice();

    m_pGUI = new GUI(GUIdesc);
}

И, наконец, WinMain:

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
                   TCHAR* cmdLine, int showCmd)
{
    PsychoBots_Game *pGameApp= new PsychoBots_Game(hInstance);

    if(pGameApp->InitApp())pGameApp->Run();
    delete pGameApp;
}

Кто-нибудь может сказать мне, в чем причина проблемы? Если вам все еще нужно больше кода, просто спросите в комментарии :)

Спасибо


person xcrypt    schedule 02.01.2012    source источник
comment
На самом деле было бы намного проще помочь вам, если бы кода было меньше. Можете ли вы привести минимальный пример с ошибкой? Или хотя бы сообщите нам строку, в которой происходит нарушение прав доступа. Отлаживать этот код с помощью подходящей IDE должно быть довольно просто.   -  person Niklas B.    schedule 02.01.2012
comment
Я постарался предоставить как можно меньше кода. Я выделю область, где возникает ошибка.   -  person xcrypt    schedule 02.01.2012
comment
Вы используете IDE? Большинство из них имеют возможность пошаговой отладки вашего кода или, по крайней мере, могут указать строку, в которой произошло нарушение прав доступа.   -  person Niklas B.    schedule 02.01.2012
comment
Да, визуальная студия. Я отказался от строки, где она прерывается, в верхней части вопроса, чтобы попытаться сделать ее более понятной.   -  person xcrypt    schedule 02.01.2012
comment
Можете ли вы добавить printf("m_pContentManager = %p\n", m_pContentManager); перед ошибочной строкой, чтобы проверить, является ли это допустимым указателем (ошибка указывает, что он равен NULL)   -  person Niklas B.    schedule 02.01.2012
comment
Инициализирован ли m_pCrosshair? Я имею в виду, что объект CrossHair должен быть создан с помощью InitGame(), но действительно ли он создает объект или конструктор возвращает ложное значение?   -  person koressak    schedule 02.01.2012
comment
@NiklasBaumstark, ты имеешь в виду m_pCrosshair? Потому что нет ничего плохого в указателе на менеджер контента?   -  person xcrypt    schedule 02.01.2012
comment
@xcrypt: да, это то, что я имел в виду.   -  person Niklas B.    schedule 02.01.2012
comment
@koressak InitGame() возвращает true, только что проверил.   -  person xcrypt    schedule 02.01.2012
comment
@NiklasBaumstark Я попробовал printf("m_pCrosshair = %p\n", m_pCrosshair); в качестве первой строки в GUI::Draw(), но когда я пытаюсь запустить код, он выдает ошибку останова! (помните, к m_pCrosshair даже нельзя получить доступ по какой-то причине), по крайней мере, не в методе Draw(), попробую в конструкторе, сек.   -  person xcrypt    schedule 02.01.2012
comment
@xcrypt: Тогда попробуйте printf("this = %p\n", this); Должен напечатать NULL. Это означает, что вы вызываете метод-член Draw для объекта NULL.   -  person Niklas B.    schedule 02.01.2012
comment
this == 0x00000000 Но я не уверен, где я могу найти результат printf(). Никогда не использовал его, пока извините.   -  person xcrypt    schedule 02.01.2012


Ответы (3)


В вашем классе есть разыменование, но вы его не видите: m_pCrosshair является членом, поэтому любой доступ будет проходить через указатель this, который, судя по ошибке, равен 0. Я не могу найти сайт вызова GUI::Draw, но указатель экземпляра там равен 0 или не инициализирован.

person thiton    schedule 02.01.2012
comment
@NiklasBaumstark: тоже может быть NULL, но нарушение прав доступа происходит в строке int a = (int)m_pCrosshair; уже в соответствии с OP. m_pCrosshair == NULL не будет проблемой в этой строке. - person thiton; 02.01.2012
comment
Странная часть: InitGame() действительно вызывается перед методом Draw(). И InitGame() действительно возвращает true. Однако, если я поставлю точку останова VS в конструкторе графического интерфейса, похоже, что он никогда не вызывается, что подозрительно. - person xcrypt; 02.01.2012

Ваш bool PsychoBots_Game::InitGame() не возвращает значение.

Вы уверены, что метод Draw вызывается в m_pGUI?

Вы уверены, что вызывается PsychoBots_Game::InitGame()? Из предоставленного вами кода вызывается только pGameApp->InitApp(). m_pGUI инициализируется в InitGame.

person marcinj    schedule 02.01.2012
comment
Да, PsychoBots_Game::InitGame() вызывается внутри pGameApp-›InitApp() и возвращает true. Извините, что не предоставил этот код, но это уже было много... - person xcrypt; 02.01.2012

Графический интерфейс класса класса не подчиняется правилу трех (хотя и содержит указатель RAW).

Таким образом, вы, вероятно, сделали копию объекта, а исходный объект был удален, в результате чего у вас остался объект с недопустимым указателем.

Есть простой способ проверить, не в этом ли проблема: сделать конструктор копирования и оператор присваивания, если GUI закрытым, если вы получаете ошибку времени компиляции, то это ваша проблема.

В качестве примечания ваш код содержит множество указателей RAW.
Вы должны посмотреть, что действительно должно быть указателем, а что может быть обычным объектом. В местах, где у вас должны быть указатели, посмотрите на использование интеллектуальных указателей.

person Martin York    schedule 02.01.2012
comment
Проблема была не в этом. И я понимаю ваше беспокойство по поводу указателей и прочего. Однако я ограничен в том, как я могу писать свой код: будучи студентом, есть определенные вещи, которые мне разрешено и запрещено делать. Насколько я ненавижу это - person xcrypt; 02.01.2012