I'm working on an MFC application, written in visual C++ in visual studio 2015. I'm calling a function of an object using a pointer to it. I get the exception "Access Violation reading location 0x4a522c31" here:
void Handler::NotifyEvent(I_Handler::eNotification nNotification){
for (t_InterfaceList::const_iterator iter = m_oClientList.begin(); iter != m_oClientList.end(); iter++){
(*iter)->I_Handler_OnEvent(nNotification);
}
}
The full error message is as follows: Exception thrown at 0x6ce42dc6 (ucrtbase.dll) in program.exe: 0xc000005: Access violation reading location 0x4a522c31. It happens when calling I_Handler_OnEvent().
The class Handler is this:
class Handler{
typedef list<I_Handler*> t_InterfaceList;
t_InterfaceList m_oClientList;
static Handler* GetInstance();
bool AddClient(I_Handler * pInterface);
bool RemoveClient(I_Handler * pInterface);
void OnTimer();
void NotifyEvent(I_Handler::eNotification nNotification);
}
The class I_Handler is this:
class I_Handler {
public:
virtual void I_Handler_OnEvent(eNotification nNotification) = 0;
};
The software works like this:
- The class Handler has a list of clients, who are of class I_Handler.
- When something happens inside OnTimer(), the clients must be notified.
- To notify them, inside OnTimer(), NotifyEvent() gets called.
- NotifyEvent() iterates over the list of clients and calls each function I_Handler_OnEvent()
I have a class somewhere else that controls a window (it's a CFormView) and it's also a client of Handler, meaning that this class is something like this:
class View_Control : public CFormView, public I_Handler{
DECLARE_DYNCREATE(View_Control)
protected:
View_Control();
virtual ~View_Control();
public:
void I_Handler_OnEvent(eNotification nNotification) override;
}
std::async is used to launch tasks in parallel in different functions inside the class Handler. Inside the function OnTimer() I check for the task to be ready with a wait_for on the future object returned by std::async. When I get std::future_status::ready, I call NotifyEvent() and everything crashes. Note that if I comment out the std::async call, then the task is not run and NotifyEvent() works as intended.
What I have tried:
I have checked and the pointer address is correct, it points to the object of class 'View_Control' who registered as client.
'AddClient' gets called inside a function of ControlView, like this:
Handler::GetInstance()->AddClient(this). I checked this and *iter, they always have different values, but are close (in one execution, *iter was 0x00595E78 and this was 0x00595DA8. However, the exception always happens reading the same address, which is nowhere near these pointers.
It looks as though the fact that a function executes in other thread created by std::async breaks the ability of NotifyEvent() to call a member function by a pointer to the object.
Why does this happen?