对类内私有数组的访问冲突

时间:2014-06-27 04:13:38

标签: c++

For the most part this is borrowed code from RasterTeks DX11 tutorial that I am modified lightly or my own use and taste.  I am getting a read access violation while using the below InputClass to set keystates.

#include "InputClass.h"

InputClass::InputClass() { }
InputClass::InputClass(const InputClass& other) { }
InputClass::~InputClass() { }

void InputClass::Initialize() {
    // Initialize all the keys to being released and not pressed.
    for (int i = 0; i<256; i++) {
        keystate[i] = false;
    }

    return;
}


void InputClass::KeyDown(unsigned int input) {
    // If a key is pressed then save that state in the key array.
    keystate[input] = true;
    return;
}


void InputClass::KeyUp(unsigned int input) {
    // If a key is released then clear that state in the key array.
    keystate[input] = false;
    return;
}


bool InputClass::IsKeyDown(unsigned int input) {
    // Return what state the key is in (pressed/not pressed).
    return keystate[input];
}

下面是我的主要回调循环,即使用WindowClass注册的循环:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        // this message is read when the window is closed
    case WM_DESTROY: {
                         PostQuitMessage(0);
                         return 0;
    }
        // Check if the window is being closed.
    case WM_CLOSE: {
                       PostQuitMessage(0);
                       return 0;
    }
    default: { return ApplicationHandle->MessageHandler(hWnd, message, wParam, lParam); }
    }
}

最后,下面是我的SystemClass的一部分辅助消息处理程序:

LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
    switch (message) {
    case WM_KEYDOWN: { input->KeyDown((unsigned int)wparam); }
    case WM_KEYUP: { input->KeyUp((unsigned int)wparam); }
    default: { return DefWindowProc(hwnd, message, wparam, lparam); }
    }
}

当代码到达辅助消息处理程序中的switch / case / default列表时,会触发异常。如果我对这些行进行评论,那么程序就会愉快地运行,但当然没有输入。

任何帮助或线索都是非常宝贵的。非常感谢你的时间。

2 个答案:

答案 0 :(得分:0)

尝试修改代码:

void InputClass::KeyDown(unsigned int input) {
    if (input < 0 || input > 255)
        return;
    // If a key is pressed then save that state in the key array.
    keystate[input] = true;
    return;
}

void InputClass::KeyUp(unsigned int input) {
    if (input < 0 || input > 255)
        return;
    // If a key is released then clear that state in the key array.
    keystate[input] = false;
    return;
}

(因为你在InputClass的构造函数中没有任何问题,这不是数组私有状态的问题)

答案 1 :(得分:0)

我试了一下,没有运气。我会在发生错误的情况下保留代码,但它在同一个地方调用了访问冲突。

我将在下面提供缺少的信息。

//inputclass.h

class InputClass
{
public:
    InputClass();
    InputClass(const InputClass&);
    ~InputClass();

    void Initialize();

    void KeyDown(unsigned int);
    void KeyUp(unsigned int);
    bool IsKeyDown(unsigned int);

//private:
    bool keystate[256];
};

//systemclass.h

#define WIN32_LEAN_AND_MEAN

#include <Windows.h>
#include <windowsx.h>
#include "InputClass.h"

class SystemClass {
public:
    SystemClass();
    ~SystemClass();

    void Startup();
    bool InitializeWindows(HWND);
    void ShutDown();
    void Run();

    LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);

    int GetWindowPosX();
    int GetWindowPosY();
    int GetWindowWidth();
    int GetWindowHeight();

private:
    HWND hWnd;
    InputClass* input;
    int posX, posY, windowWidth, windowHeight;
};

static SystemClass* ApplicationHandle = 0;

//main.cpp

#include "systemclass.h"

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreviousInstance, LPSTR lpCmdLine, int nCmdShow) {
    WNDCLASSEX wc;
    ZeroMemory(&wc, sizeof(WNDCLASSEX));
    SystemClass* system;
    system = new SystemClass;

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpszClassName = L"Engine";

    RegisterClassEx(&wc);
    system->Startup();
    if(!(system->InitializeWindows(CreateWindowEx(NULL,
                                            L"Engine",
                                            L"Engine",
                                            WS_POPUP | WS_VISIBLE,
                                            system->GetWindowPosX(),
                                            system->GetWindowPosY(),
                                            system->GetWindowWidth(),
                                            system->GetWindowHeight(),
                                            NULL,
                                            NULL,
                                            hInstance,
                                            NULL)))) return 0;
    system->Run();
    system->ShutDown();
    UnregisterClass(L"Engine", hInstance);
    delete system;
    system = 0;

    return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        // this message is read when the window is closed
    case WM_DESTROY: {
                         PostQuitMessage(0);
                         return 0;
    }
        // Check if the window is being closed.
    case WM_CLOSE: {
                       PostQuitMessage(0);
                       return 0;
    }
    default: { return ApplicationHandle->MessageHandler(hWnd, message, wParam, lParam); }
    }
}

//systemclass.cpp

#include "SystemClass.h"

SystemClass::SystemClass() { }
SystemClass::~SystemClass() { }

void SystemClass::Startup() {
    ApplicationHandle = this;
    windowWidth = GetSystemMetrics(SM_CXSCREEN);
    windowHeight = GetSystemMetrics(SM_CYSCREEN);
    input = new InputClass;
    input->Initialize();
    int fc = MessageBox(NULL, L"Engine", L"Fullscreen?", MB_YESNO);
    switch (fc) {
    case 7: {
                posX = (windowWidth - 800) / 2;
                posY = (windowHeight - 600) / 2;
                windowWidth = 800;
                windowHeight = 600;
    }
    case 6: {
                DEVMODE dmScreenSettings;
                posX = posY = 0;
                ZeroMemory(&dmScreenSettings, sizeof(dmScreenSettings));
                dmScreenSettings.dmSize = sizeof(dmScreenSettings);
                dmScreenSettings.dmPelsWidth = (unsigned long)windowWidth;
                dmScreenSettings.dmPelsHeight = (unsigned long)windowHeight;
                dmScreenSettings.dmBitsPerPel = 32;
                dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

                // Change the display settings to full screen.
                ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
    }
    }
}

bool SystemClass::InitializeWindows(HWND ihWnd) { 
    hWnd = ihWnd;
    if (hWnd) {
        //system->InitializeWindows(hWnd);
        ShowWindow(hWnd, SW_SHOW);
        SetForegroundWindow(hWnd);
        SetFocus(hWnd);
        return true;
    }
    else {
        MessageBoxEx(NULL, L"Could not create window.", L"ERROR!", MB_OK | MB_ICONEXCLAMATION, NULL);
        return false;
    }


}

void SystemClass::ShutDown() {
    delete input;
    input = 0;
    DestroyWindow(hWnd);
    hWnd = NULL;
    ApplicationHandle = NULL;
}

void SystemClass::Run() {
    bool done;
    MSG msg;
    done = false;
    while (!done) {
        // Handle the windows messages.
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        if (input->IsKeyDown(VK_ESCAPE)) { 
            done = true;
            MessageBoxEx(NULL, L"input broken.", L"ERROR!", MB_OK | MB_ICONEXCLAMATION, NULL);

        }
        // If windows signals to end the application then exit out.
        if (msg.message == WM_QUIT) { done = true; }
    }

}

int SystemClass::GetWindowPosX(){ return posX; }

int SystemClass::GetWindowPosY() { return posY; }

int SystemClass::GetWindowWidth() { return windowWidth; }

int SystemClass::GetWindowHeight() { return windowHeight; }

LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
    switch (message) {
    case WM_KEYDOWN: { input->KeyDown((unsigned int)wparam); }
    case WM_KEYUP: { input->KeyUp((unsigned int)wparam); }
    default: { return DefWindowProc(hwnd, message, wparam, lparam); }
    }
}

当我点击转义键时给出的错误消息: DX11引擎中的0x00881E08处的未处理异常2.exe:0xC0000005:访问冲突读取位置0x00000004。

好的:这是有趣的地方,本地字段中的值(特定于第二个回调函数)如下: lparam:65537 wparam:27 消息:256 hwnd:0x01b80460 {unused = ???} 这个:0x00000000

hwnd,wparam和lparam的值都以红色显示。

我觉得价值观应该告诉我这里发生了什么,但我真的不明白。变量“this”设置为地址0x00000000是否有原因?这是一个指向系统类实例的指针...或它应该是。

另外,hwnd中未使用的注释会让我失望,虽然我不确定那里出了什么问题,因为程序非常明显地至少检测到归因于窗口的按键。

我希望这可以帮助任何有想法的人。

编辑:你让我找到一个误用的指针,我发现它与“this”指针以及我使用system和ApplicationHandle的方式有关。我通过将ApplicationHandle更改为系统并在任何地方使用相同的指针来修复它。我之前使用它的方式是不合逻辑和毫无意义的。

谢谢大家帮我找到它!