max
max

Reputation: 3736

Access violation error by using pointer to creat object

so i just started windows programing with C++. First I draw some lines and it was OK, then i tried to create a class for drawing some shapes, and it's working fine when I'm using a normal method to create object (in the code these parts are commented out), but when I'm using a pointer to create new object, I get an Access violation error.

Here is my class (I've deleted some of the code so it may seems oversimplified at some parts):

class shapes {
public:
   shapes(void);
   void setstartp( POINT& p0);
   void setendp( POINT& p1);

   void draw(HDC hdc);
   ~shapes(void);

   POINT x0;
   POINT x1;
};

shapes::shapes(){}

void shapes::setstartp( POINT& p0){
    x0=p0;
}

void shapes::setendp( POINT& p1){
    x1=p1;
}

void shapes::draw(HDC hdc){
    MoveToEx(hdc,x0.x ,x0.y ,0);
    LineTo(hdc ,x1.x ,x1.y);
}

shapes::~shapes(void) {}

And this is my program, or at least the winproc part:

//shapes sh; 
shapes* sh =0;
bool mousdown =false;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    POINT p0;
    POINT p1;
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;

    switch (message)
    {
        case WM_LBUTTONDOWN :
            SetCapture(hWnd);
            mousdown = true;

            p0.x = LOWORD(lParam);
            p0.y = HIWORD(lParam);

            // sh.setstartp(p0);
            sh = new shapes();
            sh->setstartp(p0);
            break;    
     case WM_MOUSEMOVE :
         if(mousdown) {
             p1.x = LOWORD(lParam);
             p1.y = HIWORD(lParam);
             // sh.setendp(p1);
            sh->setendp(p1);
            InvalidateRect(hWnd ,0,true);
         }
         break;    
     case WM_LBUTTONUP :
         ReleaseCapture();
         mousdown = false;
         p1.x = LOWORD(lParam);
         p1.y = HIWORD(lParam);

         // sh.setendp(p1);
         sh->setendp(p1);
         InvalidateRect(hWnd ,0,true);
         break;
     case WM_PAINT:
         hdc = BeginPaint(hWnd, &ps);
         // TODO: Add any drawing code here...
         //sh.draw(hdc);
         sh->draw(hdc);
         EndPaint(hWnd, &ps);
         break;
     case WM_COMMAND: 

Here is my Access violation error :

Unhandled exception at 0x00411fda in NEWWIN.exe: 0xC0000005: Access violation reading location 0x00000004.

And error points to class implement :

 void shapes::draw(HDC hdc) {           
     MoveToEx(hdc,x0.x ,x0.y ,0);
     LineTo(hdc ,x1.x ,x1.y);
 }

Apparently there is a problem with my class properties x0 and x1 :

this 0x00000000 {x0={...} x1={...} } shapes * const

x0 {x=??? y=???} tagPOINT

x CXX0030: Error: expression cannot be evaluated

y CXX0030: Error: expression cannot be evaluated

x1 {x=??? y=???} tagPOINT

x CXX0030: Error: expression cannot be evaluated

y CXX0030: Error: expression cannot be evaluated

Upvotes: 1

Views: 886

Answers (3)

Bart van Ingen Schenau
Bart van Ingen Schenau

Reputation: 15768

Just imagine what happens if your program receives the events in this order:

  1. WM_PAINT
  2. WM_MOUSEMOVE
  3. WM_BUTTONDOWN
  4. WM_PAINT
  5. WM_MOUSEMOVE
  6. WM_BUTTONUP
  7. WM_PAINT

The shapes object is not created until event 3. arrives, but you already try to draw a shape in the first event.

The easiest fix to get rid of the crash is to check that sh is not a null-pointer (if (sh != 0) /* use sh */), or to revert back to using a non-pointer.

But there are bigger problems in your code:

  • Currently you have a memory leak, because you create a new shapes object for every WM_BUTTONDOWN event, but you never delete any of them
  • What do you want to draw if you get a WM_PAINT event before both corners of the shape are set? Currently, you draw a line to an unspecified location.

Upvotes: 0

Hans Passant
Hans Passant

Reputation: 942197

 sh->setendp(p1);

Yes, that will go kaboom. You will always get a WM_MOUSEMOVE message before you get a WM_LBUTTONDOWN message. You didn't create the sh object yet. Change

shapes* sh =0;

to

shapes sh;

for a first-order fix.

Upvotes: 1

Daniel Gehriger
Daniel Gehriger

Reputation: 7468

The problem is that you don't construct a shapes object until receiving (and handling a WM_LBUTTONDOWN) event. So if any other event (eg. WM_MOUSEMOVE) is handled before, then sh will still be 0.

Besides, note that you have a memory leak here: you call sh = new shapes(); for every WM_LBUTTONDOWN event, without ever deleting previously allocated objects.

I suggest you allocate your shape object in a WM_CREATE handler, and that you delete it in a WM_DESTROY handler.

Upvotes: 3

Related Questions