Click to See Complete Forum and Search --> : [RESOLVED] std::map throwing access violation


cheeseboy
December 8th, 2006, 02:51 AM
I'm making a basic window class using a std::map to hold event handlers. But when I call handlers.find(message) I get an access violation. I've traced it to handlers._MyBase._Root(), at which point the _Tree's head node seems to be undefined.

Abridged:

class Window {
public:
Window():hw(0)
{
handlers[0]=&Test;
}
int Create()
{
//makes the window with default settings
}
int AddHandler(UINT message, MessageHandler in)
{
handlers[message]=in;
return 0;
}
private:
static LRESULT CALLBACK Window::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
Window *window;
if(msg==WM_CREATE){
CREATESTRUCT *c=(CREATESTRUCT *)lParam;
window = (Window *)c->lpCreateParams;
SetWindowLong(hWnd, GWL_USERDATA, (long)window);
return 0;
} else {
window = (Window *)GetWindowLong(hWnd, GWL_USERDATA);
}
return window->HandleMessage(msg, wParam, lParam);
}
HWND hw;
HandlerList handlers;
};


std::map works fine outside of the class, or in a dummy class, but when I try to make a class like this one, it fails, and I don't know why. Can someone help?

Calculator
December 8th, 2006, 03:00 AM
Do you add the handlers before you do a createwindow? You know that map::find returns an iterator past the last element in the map if your request is not found?

cheeseboy
December 8th, 2006, 03:25 AM
Yes, I am adding handlers before I call Create(), and yes, I am checking to see if the iterator equals handlers.end() after find, but at handlers.find, the program crashes.

Paul McKenzie
December 8th, 2006, 05:52 AM
I've traced it to handlers._MyBase._Root(), at which point the _Tree's head node seems to be undefined.But you haven't traced it to where it gets undefined.

Abridged:

The problem is that "Abridged" code will not help in others finding the problem. Your issue occurs during the running of your program, and unless we have all of your code, you can get very little help.

There is too much code missing, we don't know when, where, or how this class is used, we have no driver function to see the class in action, etc.
std::map works fine outside of the class, or in a dummy class, but when I try to make a class like this one, it fails,The std::map doesn't fail if used properly, and your code is not enough to show us exactly what is going on.

Regards,

Paul McKenzie

Paul McKenzie
December 8th, 2006, 05:56 AM
Yes, I am adding handlers before I call Create(), and yes, I am checking to see if the iterator equals handlers.end() after find, but at handlers.find, the program crashes.What is the value of the Window object? Is it valid? If not, then you are accessing members of an invalid object.

If it is valid, then you probably have corrupted memory somewhere in your program. Also, in the code you did post, you are assigning the value of the address of "Test" to handler[0]. What is "Test"? Is the address valid, i.e. has it gone out of scope? Again, you need to post a real program so that all of these questions can be answered.

Regards,

Paul McKenzie

cheeseboy
December 8th, 2006, 02:24 PM
Okay


//file: main.cpp
#include <windows.h>
#include <iostream>
#include <map>
typedef void(*MessageHandler)(WPARAM wParam, LPARAM lParam);
typedef std::map<UINT, MessageHandler> HandlerList;
const int error = -1;
class Window {
public:
Window():hw(0)
{
}
~Window()
{
}
int Create()
{
WNDCLASSEX wc;
wc.cbClsExtra=0;
wc.cbSize=sizeof(WNDCLASSEX);
wc.cbWndExtra=0;
wc.hbrBackground=(HBRUSH)COLOR_BACKGROUND;
wc.hCursor=LoadCursor(NULL, IDC_ARROW);
wc.hIcon=LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);
wc.hInstance=GetModuleHandle(NULL);
wc.lpfnWndProc=WndProc;
wc.lpszClassName="Window";
wc.lpszMenuName=NULL;
wc.style=NULL;
RegisterClassEx(&wc);

HINSTANCE hInstance=GetModuleHandle(NULL);
hw=CreateWindowEx(NULL,
"Window",
"test",
WS_OVERLAPPEDWINDOW,
0, 0, 50, 50,
NULL,
NULL,
hInstance,
this);
if(NULL==hw)
{
return error;
}
return 0;
}
int HandleMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
HandlerList::iterator it;
it = handlers.find(message);
if(it!=handlers.end()){
it->second(wParam, lParam);
return 0;
}
return DefWindowProc(this->hw, message, wParam, lParam);
}
int AddHandler(UINT message, MessageHandler in)
{
handlers[message]=in;
return 0;
}
int Show(){
MSG messages;
while (GetMessage(&messages, NULL, 0, 0))
{
DispatchMessage(&messages);
}
return messages.wParam;
}
private:
static LRESULT CALLBACK Window::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
Window *window;
if(msg==WM_CREATE){
CREATESTRUCT *c=(CREATESTRUCT *)lParam;
window = (Window *)c->lpCreateParams;
SetWindowLong(hWnd, GWL_USERDATA, (long)window);
return 0;
} else {
window = (Window *)GetWindowLong(hWnd, GWL_USERDATA);
}
return window->HandleMessage(msg, wParam, lParam);
}
HWND hw;
HandlerList handlers;
};
void paint(WPARAM w, LPARAM l){
MessageBox(NULL, "", "paint", MB_OK);
}
int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
Window test;
test.AddHandler(WM_PAINT, paint);
test.Create();
return test.Show();
}


Thanks for helping

Calculator
December 8th, 2006, 04:21 PM
Okay, I could be wrong here, but I think that a WM_NCCREATE message is sent before a WM_CREATE message. If this is the case, you would probably get an access violation. But, you have explained that it occured in the map::find, so I'm not sure.

Paul McKenzie
December 8th, 2006, 04:59 PM
OkayHere is the first sentence of my previous post:
What is the value of the Window object? Is it valid?The Window object is not valid. I ran your code, and the value of this is NULL in the function HandleMessage().

Just put a breakpoint in HandleMessage(), and you will see that accessing "handlers" is invalid, since the Window object is invalid. It all starts from Window::WndProc.

But seriously, the error is obvious by just debugging the code, since you could find the problem in literally seconds by just putting a breakpoint in the code and inspecting the data (or are you not using a debugger??).

Regards,

Paul McKenzie

cheeseboy
December 8th, 2006, 09:13 PM
I am using a debugger, but I'm quite the noob when it comes to debuggers, and indeed, C in general, and hadn't looked there.

Thanks Paul and Calculator, with your help I've managed to fix it.

For anyone else,

static LRESULT CALLBACK Window::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
Window *window;
window = (Window *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if(msg==WM_CREATE){
CREATESTRUCT *c=(CREATESTRUCT *)lParam;
MessageBox(NULL, "", "wm_create", MB_OK);
window = (Window *)c->lpCreateParams;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (long)window);
window->HandleMessage(msg, wParam, lParam);
return 0;
}
if(window!=NULL){
if(window->HandleMessage(msg, wParam, lParam)!=error){
return 0;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}