deleteオペレータについて


#include
class Base1
{
public:
virtual ~Base1(){}
};
class Base2
{
public:
virtual void f()=0;
//virtual ~Base2(){};
};
class Derive:public Base1,public Base2
{
public:
void f(){std::cout<<"f";}
~Derive(){std::cout<<"Derive dtor";}
};
void func(Base2* p)
{
p->f();
}
int main(int , char**)
{
Derive *p = new Derive;
Base1 *pb1=p;
Base2 *pb2=p;
func(p);
delete p;
//delete pb1;
//delete pb2;
}
このコードはbase 2の虚dtorとmainのdelete pb 2を変更することでcrashを招きます.
いわゆるdeleteは2つのステップに分けられ、runtimeはdeleteに遭遇したとき、理論的にdelete operatorというものを呼び出し、これはまずdtorを呼び出し、operator deleteを呼び出してメモリを解放します.リロードできるのはoperator deleteですが、delete operatorはリロードできません.Openator deleteでは、メモリの解放のみを担当するvoid*をパラメータとして受け入れます.では、あなたのlayoutによると、pb 1とdが指すメモリアドレスは違います.Base 1にはサイズがあるので、pb 2にはオフセットがあります.したがってoperator deleteにとってpb 2に渡すとそのままoverになります.では、delete operatorはどのようにアドレスを正しく伝えるべきかを知ることができますか?これはdelete operatorがvirtualに似ているからです.このvirtual特性を実現するための前提条件は、あなたのdtorがvirtualでなければならないことです.これはvirtualを注釈するとoverになる理由を説明することができます.

 
  1. static void* operator new (size_t size ) {
  2. void* p=:: operator new (size );
  3. std:: cout<< "Base2 new: "<<std:: hex<<p<< "
    "
    ;
  4. return p;
  5. }
  6. static void operator delete ( void* p ) {
  7. std:: cout<< "Base2 del: "<<std:: hex<<p<< "
    "
    ;
  8. :: operator delete (p );
  9. }

ポインタが指すメモリを印刷することができ、pb 1とpb 2とpが異なることがわかります.プログラムがどのoperator deleteに入るかに注意してください.関連資料の詳細は
effective c++ 7