At first, see [ virtual method table in wikipedia ].
'pointer fixups' is needed to support inheritance in C++.
Let's dig deeper.. See following example. (classes comes from above Wikipedia).
// <CASE 1> #ifdef _CASE_1_ class B1 { public: void f0() {} virtual void f1() {} int int_in_b1; }; class B2 { public: virtual void f2() {} int int_in_b2; }; class D : public B1, public B2 { public: void d() {} void f2() {} // override B2::f2() int int_in_d; }; #endif // _CASE_1_ // <CASE 2> #ifdef _CASE_2_ class B1 { public: virtual ~B1(){} void f0() {} virtual void f1() {} int int_in_b1; }; class B2 { public: virtual ~B2(){} virtual void f2() {} int int_in_b2; }; class D : public B1, public B2 { public: ~D(){} void d() {} void f2() {} // override B2::f2() int int_in_d; }; #endif // _CASE_2_ void funcA(B1* obj) { // -------- (*1) } void funcB(B2* obj) { // -------- (*2) } void main() { D* p = new D; funcA(dynamic_cast<B1*>(p)); // -------- (*a) funcB(dynamic_cast<B2*>(p)); // -------- (*b) // delete p; // ----- (*l) // delete (dynamic_cast<B1*>(p)); // ----- (*m) // delete (dynamic_cast<B2*>(p)); // ----- (*n) }
We can see that pointer 'p' is passed as parameter in (*a) and (*b). And to do this type-casting and 'pointer fixup' is needed. That is, actual memory address passed as parameter of (*a) is different from the one of (*b). This is 'pointer fixup'. In case of GCC and MSVC7, there is 8-byte-gap as above wikipedia said.; { Address_of_obj_at_(*1) + 8 = Address_of_obj_at_(*2) }.
That's OK. It's very common.
Then, what happen at the moment of deleting memory?
We may guess that memory address passed is same in (*l) and (*m), but not in (*n) - may be 8-byte-gap in GCC and MSVC7 same as the case of (*a) and (*b). In <CASE_1>, program works just as we expects. (*l) and (*m) don't make an exception at runtime, but (*n) does. Then, as you know, why <CASE_2> works well? Newly assigned memory is deleted correctly in <CASE_2>. Than, is it really true that passed addresses are different among (*l), (*m) and (*n)? To investigate deeper, I tested it again with overloaded new/delete operator.
void * operator new(size_t size) { return malloc(size); // ------ (*A) } void operator delete(void *p) { return free(p); // ----- (*B) }
We can check passed address at (*B). In <CASE_1>, 'p' at (*B) is same with 'obj' at (*2), and error is raised - memory address trying to free is different with allocated one. Difference between <CASE_1> and <CASE_2> is destructor declared as 'virtual'. Interestingly, in <CASE_2>, 'p' at (*B) is the value of 'obj' at (*1) - original address -, and work successfully. In summary, if 'virtual destructor' is defined, than original address value is passed to 'delete' operator. It is interesting, isn't it?. :-)
'Language > C&C++' 카테고리의 다른 글
[C/C++] Take care of using shallow copy! (0) | 2008.06.04 |
---|---|
[C/C++] Using Reference as function parameter... (0) | 2008.05.02 |
[C/C++] Simple example of using 'typename' (0) | 2008.04.22 |
[C/C++] Abusing throwing exception drops performance severely. (0) | 2008.04.10 |
[C/C++] Attention! Integer-operation to avoid float-operation... (0) | 2008.03.21 |