Векторная проблема Win32 API в обратном вызове

В обратном вызове WndProc моей программы я делаю это, чтобы сохранить щелчок мыши в векторе:

case WM_LBUTTONDOWN:
    point = new POINT();
    point->x = LOWORD (lParam);
    point->y = HIWORD (lParam);

    point_vector.push_back(point);

    InvalidateRect(hWnd, NULL, TRUE);
    break;

Он компилируется нормально, но когда он запускается, я получаю нарушение прав доступа к «push_back». И «point», и «point_vector» объявлены глобально и кажутся действительными в отладчике. Если я объявлю их локально, нарушения прав доступа нет. Почему это могло произойти?

Это на VS10.

@Martyn Lovell Вот стек вызовов

msvcr100d.dll! operator delete (void * pUserData = 0xfefefefe) Строка 52 + 0x3 байта C ++ my_app.exe! std :: allocator :: deallocate (tagPOINT * * _Ptr = 0xfefefefe, unsigned int формальный = 0) Строка 182 + 0x9 байт C ++ my_app.exe! Std :: vector> :: reserve (unsigned int _Count = 1) Строка 768 C ++ my_app.exe! Std :: vector> :: _ Reserve (unsigned int _Count = 1) Строка 1298 C ++ my_app.exe ! std :: vector> :: push_back (tagPOINT * const & _Val = 0x008e9d58) Строка 992 C ++ my_app.exe! WndProc (HWND * hWnd = 0x000b060a, unsigned int message = 513, unsigned int wParam = 1, long lParam = 19857987) Строка 241 C ++ user32.dll! 774662fa ()
[Фреймы ниже могут быть неправильными и / или отсутствующими, символы для user32.dll не загружены]
user32.dll! 77466d3a ()
user32 .dll! 77466ce9 ()
user32.dll! 77466e44 ()
user32.dll! 774677c4 ()
user32.dll! 7746788a ()
my_app.exe! wWinMain (HINSTANCE__ * hInstance = 0x00c80000 , HINSTANCE__ * hPrevInstance = 0x00000000, wc har_t * lpCmdLine = 0x006c35d2, int nCmdShow = 1) Строка 62 + 0xc байтов C ++ my_app.exe! __ tmainCRTStartup () Строка 547 + 0x2c байтов C my_app.exe! wWinMainCRTStartup () Строка 371c kernel32ca () 764 ntdll.dll! 77e79ed2 ()
ntdll.dll! 77e79ea5 ()

И это строка, в которой происходит сбой в dbgdel.cpp (не уверен, что это полезно) / * проверка типа блока * / _ASSERTE (_BLOCK_TYPE_IS_VALID (pHead-> nBlockUse));

@CoreyStup Кажется, нет никакой разницы, являются ли вары локальными или глобальными

Также это происходит, если я вызываю другие векторные функции, такие как resize (), clear () или reserve (), но не size ().


person Mossen    schedule 13.06.2011    source источник
comment
FWIW ваш фрагмент кода отлично работает для меня.   -  person Chris O    schedule 14.06.2011
comment
Почему вы динамически выделяете такой крошечный тип, как POINT? Копирование, вероятно, происходит быстрее, чем передача указателя.   -  person Ben Voigt    schedule 14.06.2011
comment
Что такое стек вызовов сбоя?   -  person Martyn Lovell    schedule 14.06.2011
comment
Я бы предположил, что глобальный point_vector где-то забивается памятью. Будет ли действовать иначе, если вы перемещаете point_vector vs point как локальные, по одному?   -  person CoreyStup    schedule 14.06.2011
comment
Как вы объявляете point_vector? Это вектор указателей на ТОЧКИ или просто вектор ТОЧЕК?   -  person Adrian McCarthy    schedule 15.06.2011
comment
Я объявляю это так: std :: vector ‹POINT *› point_vector;   -  person Mossen    schedule 15.06.2011
comment
Это маловероятно, но возможно ли, что WndProc и вектор, определенные в глобальной области видимости, находятся в другом сегменте памяти (например, в длинном сегменте ptr)?   -  person Mossen    schedule 15.06.2011
comment
Я поработал над этим еще немного. Я не вижу ошибки, если собираю в режиме выпуска. Только режим отладки вызывает нарушение прав доступа.   -  person Mossen    schedule 15.06.2011


Ответы (2)


Оба "point" и "point_vector" ... кажутся действительными в отладчике.

  • Как вы думаете, в какой мере они действительны? Стек вызовов подразумевает обратное.
  • Как это выглядит до первой попытки push_back?

Это вершина стека вызовов:

6. msvcr100d.dll!operator delete(void * pUserData=0xfefefefe) Line 52 + 0x3 bytes C++
5. my_app.exe!std::allocator::deallocate(tagPOINT * * _Ptr=0xfefefefe, unsigned int formal=0) Line 182 + 0x9 bytes C++
4. my_app.exe!std::vector >::reserve(unsigned int _Count=1) Line 768 C++
3. my_app.exe!std::vector >::_Reserve(unsigned int _Count=1) Line 1298 C++
2. my_app.exe!std::vector >::push_back(tagPOINT * const & _Val=0x008e9d58) Line 992 C++
1. my_app.exe!WndProc(HWND * hWnd=0x000b060a, unsigned int message=513, unsigned int wParam=1, long lParam=19857987) Line 241 C++

Давайте рассмотрим это с самого начала:

1. my_app.exe!WndProc(HWND * hWnd=0x000b060a, unsigned int message=513, unsigned int wParam=1, long lParam=19857987) Line 241 C++

В 1 выше WM_LBUTTONDOWN прибывает в WndProc.

2. my_app.exe!std::vector >::push_back(tagPOINT * const & _Val=0x008e9d58) Line 992 C++

В приведенном выше пункте 2 вы вызываете push_back с указателем на вновь созданный экземпляр POINT в куче.

3. my_app.exe!std::vector >::_Reserve(unsigned int _Count=1) Line 1298 C++

В 3 выше push_back вызывает внутреннюю функцию _Reserve со счетом 1, чтобы выделить память для 1 POINT*. Это связано с тем, что вектор пуст, поскольку ни один элемент еще не был добавлен, а схема экспоненциального роста этого конкретного распределителя экземпляров вектора начинается с 1. (Добавление другого элемента приведет к перераспределению новой памяти и копированию первого элемента плюс новый. там.)

4. my_app.exe!std::vector >::reserve(unsigned int _Count=1) Line 768 C++

В пункте 4 выше _Reserve перенаправляет свой вызов резервной функции.

5. my_app.exe!std::allocator::deallocate(tagPOINT * * _Ptr=0xfefefefe, unsigned int formal=0) Line 182 + 0x9 bytes C++

В 5 выше, после выделения пространства для первого POINT*, резервный видит, что внутренний указатель векторных данных (в VS 2010 его имя _Myfirst) не равен нулю (см. _Ptr = 0xfefefefe выше), поэтому перед его указанием на новое пространство только что выделенное, старое пространство из 0 (!) POINT* элементов должно быть освобождено.

К сожалению, allocator :: deallocate игнорирует, что 0 элементов должны быть освобождены (это может быть неработоспособность), и с радостью пытается удалить 0xfefefefe.

6. msvcr100d.dll!operator delete(void * pUserData=0xfefefefe) Line 52 + 0x3 bytes C++

В пункте 6 выше 0xfefefefe, к сожалению, является отладочным представлением VS уже освобожденной памяти, поэтому удалите дроссели. Что еще он умеет?

  • Но почему внутренний указатель векторных данных 0xfefefefe?
  • Что вы на самом деле сделали с вектором до того, как попробовали push_back?
  • Как именно вы объявили вектор?

Странно это.

person Johann Gerell    schedule 14.06.2011

ОК, решил. В другой части моей программы я звонил:

_stprintf_s(msgbuf, 1024, _T("Mouse coordinates: %d %d\0"), mouse.x, mouse.y);

Должно было

_stprintf_s(msgbuf, sizeof(msgbuf), _T("Mouse coordinates: %d %d\0"), mouse.x, mouse.y);

Это привело к некоторому повреждению памяти, потому что длина msgbuf! = 1024

Я такая жопа. Извинения всем

person Mossen    schedule 14.06.2011
comment
@Johann: С каких это пор _st_printf_s что-нибудь освобождает? Конечно, он перезаписывает переданный вами буфер до указанной вами длины. - person Ben Voigt; 15.06.2011