Попытка передать функцию-член структуры atexit

Я пишу отладчик на C ++, и при выходе он мне нужен для очистки любых точек останова, установленных в отладчике.

Я сделал struct называется BREAKPOINT_INFO которая содержит информацию, необходимую для очистки каждой точки останова. Информация, такая как дескриптор процесса (hProcess) адрес виртуальной памяти точки останова (lpBreakPoint) и код операции оригинальной инструкции, которая была заменена (instr).

Тогда у меня есть CleanUp функция-член, которая использует элементы данных, описанные выше, чтобы восстановить исходную инструкцию, чтобы отладчик не падал.

typedef struct
{
HANDLE hProcess;

PCHAR  lpBreakPoint;

CHAR   instr;

void CleanUp()
{
DWORD dwError = 0;
std::ostringstream oss;
LPSTR szErrorRest = (LPSTR)"Error restoring original instruction: ";

if(!WriteProcessMemory(hProcess, lpBreakPoint, &instr, sizeof(CHAR), NULL))
{
dwError = GetLastError();

oss << szErrorRest << dwError;

szErrorRest = oss.str().c_str();

MessageBox(NULL, szErrorRest, "ERROR", MB_OK|MB_ICONERROR);
}
}
}BREAKPOINT_INFO, *PBREAKPOINT_INFO;

Тем не менее, когда я пытаюсь передать свою функцию-член для каждого BREAKPOINT_INFO структура, я получаю ошибку компиляции:

C:\...\...\main.cpp|39|error: cannot convert 'BREAKPOINT_INFO::CleanUp' from type 'void (BREAKPOINT_INFO::)()' to type 'void (__attribute__((__cdecl__)) *)()'|

И даже после попытки привести к этому типу он не может скомпилироваться. Можно ли передать функцию-член atexit? И если так, как бы я поступил так? Спасибо за ваше время.

2

Решение

Нет, вы не можете передать ничего, кроме указателя на функцию atexit, как указано в его декларации.

int atexit (void (*func)(void)) noexcept

Функция-член не свободная функция.
Как вы можете видеть в сообщении об ошибке, оно имеет тип void (BREAKPOINT_INFO::)() который не такой же как void (),

Фактически указатель на функцию-член принимает дополнительный первый параметр, чтобы указать, какой экземпляр класса вызывает функцию-член.

auto member_function_pointer = BREAKPOINT_INFO::CleanUp;
BREAKPOINT_INFO some_info;
member_function_pointer(&some_info);  //is equivalent to...
some_info.CleanUp();

И нет, ты не могу передать захват лямбда в качестве указателя на функцию. Не захватив лямбда имеет общедоступная не виртуальная неявная функция преобразования констант в указатель на функцию, что может быть источником неправильного представления о том, что указатель на функцию может указывать на другие вещи.

Вместо этого, как уже упоминалось в комментариях, вы должны использовать деструктор для очистки. Эта модель известна как RAII, и, безусловно, один из лучших.


Как знак, тебе не нужно сводить с ума typedef на struct объявления в C ++, то, что вы пишете, очень похоже на C с методами.

2

Другие решения

Изначально я не собирался писать ответ, поскольку, хотя он и будет правильным и правдивым, он будет приглашать — голосовать, но, тем не менее, это так.

Вы наверняка МОЖЕТЕ передать захватывающий лямбда-объект atexit(), если ты cify это во-первых, вот пример:

int a = 10;

std::atexit(cify<void(*)()>([a](){std::cout << a << std::endl;}));

но, чтобы решить вашу проблему, я бы предпочел использовать выход из области схема.

Если вы захватите указатель или ссылку на экземпляр какого-либо класса, вы сможете получить доступ к его членам.

1