I’ve been messing about with member-function pointers in relation to a previous question. In the code below I call methods on a class (B) that change a variable (count) in it, but I never make an instance of this class. Why does this work?
#include <iostream>
#include <string>
#include <map>
class A;
typedef int (A::*MEMFUNC)(int, int);
#define HANDLER(aclass, aproc) (MEMFUNC)(&aclass::aproc)
enum
{
ADD=1,
MUL,
SUB,
DIV
};
class B
{
int count;
public:
B() : count(0) {}
~B() {}
int multiply(int x, int y) { count++; return x*y*count; }
int divide(int x, int y) { count++; if (y!=0) return (x/y)*count; else return 0; }
};
class A
{
std::map< int, MEMFUNC > funcs;
public:
A() { AddLocals(); }
~A() {}
int CallLocal(int nID, int x, int y)
{
MEMFUNC f = funcs[nID];
if (f) return (this->*f)(x, y);
else return 0;
}
void AddLocals()
{
Add(ADD, HANDLER(A, plus));
Add(MUL, HANDLER(B, multiply));
Add(SUB, HANDLER(A, subtract));
Add(DIV, HANDLER(B, divide));
}
void Add(int nID, MEMFUNC f) { funcs[nID] = f; }
int plus(int x, int y) { return x+y; }
int subtract(int x, int y) { return x-y; }
};
int main()
{
A aA;
int a,b,c,d;
a = aA.CallLocal(ADD,8,2);
b = aA.CallLocal(MUL,8,2);
c = aA.CallLocal(SUB,8,2);
d = aA.CallLocal(DIV,8,2);
std::cout << "a = " << a << "\n"
<< "b = " << b << "\n"
<< "c = " << c << "\n"
<< "d = " << d << "\n";
return 0;
}
(sorry, me again, but this member-function pointers are making me itch)
The result is just undefined behavior. For example, I get that
b = 2083899728andd = -552766888.The persistent thing you are manipulating is most likely an int’s worth of bytes in the map instance of A (because if the object were indeed a B, then that’s the offset where the
countmember would be located.In my stdlib implementation, the first member of map is the comparison function, in this case an instance of
std::less<int>. Its size is 1, but there must be unused padding bytes after that to align the other members of map. That is, (at least) the first four bytes of this instantiation ofstd::mapcontains just garbage that is not used for anything (std::less doesn’t have data members and doesn’t store state, it just takes space in the map). That would explain why the code doesn’t crash – it is modifying a part of the map instance which doesn’t affect the functioning of the map.Add more data members in B before
count, and nowcount++will affect crucial parts of the map’s internal representation and you can get a crash.