【问题标题】:Access violation error by using pointer to creat object使用指针创建对象的访问冲突错误
【发布时间】:2026-02-23 23:20:10
【问题描述】:

所以我刚刚开始使用 C++ 进行 Windows 编程。首先我画了一些线,没关系, 然后我尝试创建一个用于绘制一些形状的类,当我使用普通方法创建对象时它工作正常(在代码中这些部分被注释掉), 但是当我使用指针创建新对象时,出现Access violation 错误。

这是我的课程(我已经删除了一些代码,因此在某些部分可能看起来过于简单):

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) {}

这是我的程序,或者至少是winproc 部分:

//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: 

这是我的Access violation 错误:

在 0x00411fda 处未处理的异常 NEWWIN.exe:0xC0000005:访问 违规读取位置0x00000004。

并且错误指向类实现:

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

显然我的类属性x0x1 有问题:

这个 0x00000000 {x0={...} x1={...} } 形状 * 常量

x0 {x=??? y=???} 标记点

x CXX0030:错误:表达式不能 评价过

y CXX0030:错误:表达式不能 评价过

x1 {x=??? y=???} 标记点

x CXX0030:错误:表达式不能 评价过

y CXX0030:错误:表达式不能 评估

【问题讨论】:

  • 用C++做win32开发是自己的选择吗?我首先在 C# 中进行原型设计,然后将结果相关的内容移植回来。
  • 是的,我的目标是开始 Directx 编程。

标签: c++ oop pointers windows


【解决方案1】:

问题是在接收(并处理WM_LBUTTONDOWN)事件之前,您不会构造shapes 对象。所以如果之前处理过任何其他事件(例如WM_MOUSEMOVE),那么sh 仍然是0。

此外,请注意这里存在内存泄漏:您为每个 WM_LBUTTONDOWN 事件调用 sh = new shapes();,而从未删除以前分配的对象。

我建议您将shape 对象分配到WM_CREATE 处理程序中,并将delete 分配到WM_DESTROY 处理程序中。

【讨论】:

  • thanx 这个想法是创建不同的类来绘制不同的形状,并且“形状”类是这些类的抽象父类,因为我说我删除了这些部分以找出问题的根源,现在用户将从菜单中选择形状,因此应该在 WM_LBUTTONDOWN 上创建对象我想我可以使用“if (sh != 0)”来检查 WM_PAINT 上的对象
  • 好的 - 是的,if (sh) { ... } 很好。而且我假设您保留了一个形状对象列表,并且您的实际程序中没有内存泄漏。
  • 是的,有一个向量要存储我的对象,或者我应该说我的指针,所以我需要删除“sh”对象以及 WM_DESTROY 上的向量吗?用户可以在关闭窗口之前绘制 20 条线。在绘制每一行之后我需要销毁“sh”对象还是在 WM_DESTROY 上删除一次就足够了?
  • 您需要保留所有形状对象,直到 WM_DESTROY。那是因为在 WM_PAINT 中,您应该重绘所有现有的形状(实际上,只有那些在脏窗口区域中的形状)。所以是的,在 WM_DESTROY 中,循环遍历向量中的所有形状并对它们调用 delete(或首先使用智能指针)。然后删除该向量(如果它已在堆上分配)。
【解决方案2】:
 sh->setendp(p1);

是的,那将会大放异彩。在收到 WM_LBUTTONDOWN 消息之前,您总是会收到 WM_MOUSEMOVE 消息。您还没有创建 sh 对象。改变

shapes* sh =0;

shapes sh;

一阶修复。

【讨论】:

    【解决方案3】:

    想象一下如果您的程序按此顺序接收事件会发生什么:

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

    shapes 对象在事件 3. 到来之前不会创建,但您已经尝试在第一个事件中绘制形状。

    摆脱崩溃的最简单解决方法是检查sh 是否不是空指针 (if (sh != 0) /* use sh */),或者恢复使用非指针。

    但是您的代码中存在更大的问题:

    • 目前您存在内存泄漏,因为您为每个 WM_BUTTONDOWN 事件创建了一个新的 shapes 对象,但您从未删除任何一个对象
    • 如果在设置形状的两个角之前收到 WM_PAINT 事件,您想绘制什么?目前,您绘制一条线到一个未指定的位置。

    【讨论】:

    • @max:这就是事件的问题。他们可能会以完全出乎意料的顺序出现。如果事件 B 的处理程序生成了该事件,则只能假设事件 B 跟随事件 A。即便如此,中间可能还会发生其他事件。