Use the deferred virtual call mechanism to avoid the virtual
call bug in the constructor. See docs/wrong_virtual_call.md for a description.
This commit is contained in:
parent
0b6cdeb5f5
commit
5e76b49cae
6 changed files with 64 additions and 11 deletions
25
docs/wrong_virtual_call.md
Normal file
25
docs/wrong_virtual_call.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
1) SizeNotifiable, defined as the following:
|
||||
|
||||
class SizeNotifiable<RegisterBehaviour, true> : private RegisterBehaviour, public SizeNotifiableBase { ... };
|
||||
|
||||
gets constructed - it inherits from SizeNotifiableBase which declares NotifyResChanged() as virtual. It also inherits from RegisterBehaviour, which must provide a Register() method.
|
||||
|
||||
2) In SizeNotifiable's constructor RegisterBehaviour::Register(this) gets called. Being in the constructor, virtual calls on this are UB.
|
||||
|
||||
3) When RegisterBehaviour == AutoRegister, we have Register defined as the following:
|
||||
|
||||
void AutoRegister::Register (SizeNotifiableBase* parNotifiable) {
|
||||
m_id = m_sdlmain->RegisterForResChange(parNotifiable);
|
||||
}
|
||||
|
||||
note that parNotifiable is received from SizeNotifiable's constructor, so it's a partially constructed object.
|
||||
|
||||
4) RegisterForResChange() is defined as:
|
||||
|
||||
size_t SDLMain::RegisterForResChange (SizeNotifiableBase* parNotif) {
|
||||
parNotif->NotifyResChanged(m_localData->sizeratio);
|
||||
return m_localData->resChangeNotifList.Add(parNotif);
|
||||
}
|
||||
|
||||
parNotif is, again, the partly constructed object pointed by this in SizeNotifiable's constructor. NotifyResChanged() is a virtual method, thus the bug.
|
||||
Objects being registered need to be notified straight away since they have no clue about the current size held by SDLMain.
|
Loading…
Add table
Add a link
Reference in a new issue