Consider the following code:
#include
struct foo
{
// (a):
void bar() { std::cout << \"gman was here\" << std::endl; }
Obviously undefined means it's not defined, but sometimes it can be predictable. The information I'm about to provide should never be relied on for working code since it certainly isn't guaranteed, but it might come in useful when debugging.
You might think that calling a function on an object pointer will dereference the pointer and cause UB. In practice if the function isn't virtual, the compiler will have converted it to a plain function call passing the pointer as the first parameter this, bypassing the dereference and creating a time bomb for the called member function. If the member function doesn't reference any member variables or virtual functions, it might actually succeed without error. Remember that succeeding falls within the universe of "undefined"!
Microsoft's MFC function GetSafeHwnd actually relies on this behavior. I don't know what they were smoking.
If you're calling a virtual function, the pointer must be dereferenced to get to the vtable, and for sure you're going to get UB (probably a crash but remember that there are no guarantees).