1

独自のメモリ割り当てを使用する適切なクラスの設計に問題があります。このことを考慮:

class IAbstract { ... };
class CConcrete : public IAbstract { ... };

私はこのようなことをしたい:

IAbstract *ptr = new CConcrete();
delete ptr;

問題は、CConcrete の「新規」にメモリ アロケータを使用してもらいたいということです。また、「削除」で適切なデアロケータを使用したい。ただし、new と delete は静的関数であるため、上記の例の delete は CConcrete の delete を呼び出しません (delete が仮想の場合は呼び出します)。

これを解決する 1 つの方法は、次のようなものを作成することです。

class IAbstract {
public:
   virtual Delete(void* ptr)=0;
   void operator delete(void* ptr) {

      ((IAbstract*)(ptr))->Delete(ptr);
   }
}; 

派生クラスで Delete をオーバーライドします。しかし、このソリューションはかなり醜く、特に ptr を IAbstract* にキャストします。

それを行うより良い方法はありますか?

4

3 に答える 3

0

最初の面白いことは、voidポインターをキャストしてメンバー関数を呼び出すことができないことです。技術的にはコンパイルされますが、オブジェクト(またはオブジェクト階層)が破棄された後(デストラクタを呼び出すことによって)、演算子deleteが呼び出されます。言い換えると、破棄されたクラスのvtableにアクセスしようとしているため、実行しているのはUBです。

もう1つのことは、デストラクタが仮想である限り、適切な削除演算子がクラスで呼び出されることです。したがって、その上に追加のvtableリソースを使用して独自のメカニズムを再発明する必要はありません。私は次のアプローチがあなたが探しているものだと思います:

#include <new>
#include <cstdio>
#include <cstdlib>

class Base {
  public:
    Base() { }
    virtual ~Base() { printf("Base::~Base()\n"); }
};

class Derived : public Base {
    char data[256];

  public:
    Derived() {}
    virtual ~Derived() { printf("Derived::~Derived()\n"); }

    void *operator new(size_t size)
    {
        void *p = malloc(size);
        printf("Allocated %lu bytes @ %p\n", size, p);
        return p;
    }

    void operator delete(void *ptr)
    {
        printf("Freeing %p\n", ptr);
        free(ptr);
    }
};

int main()
{
    Base *b = new Base();
    delete b;
    b = new Derived();
    delete b;
}

ただし、仮想デストラクタを削除するとすぐに、オーバーロードされた演算子deleteが呼び出されないことを忘れないでください。

于 2012-10-26T17:07:35.227 に答える
0

コードの多くを省略しているため、コードの何が問題になっているのかを正確に知ることは困難です。私にできる最善のことは、実際に機能するプログラムを紹介することです。

このプログラムを検討してください。

#include <iostream>
#define X() (std::cout << __PRETTY_FUNCTION__ << "\n")

class IAbstract {
public:
  virtual ~IAbstract() { X(); }
};
class CConcrete : public IAbstract {
public:
  void* operator new(size_t sz) {
    X();
    return ::operator new(sz); // or however you allocate memory
  }
  void operator delete(void* p) {
    X();
    ::operator delete(p); // or however you de-allocate memory
  }
  ~CConcrete() { X(); }
};

int main () {
  IAbstract *ptr = new CConcrete();
  delete ptr;
}

私のコンピューターの出力は次のとおりです。

static void* CConcrete::operator new(size_t)
virtual CConcrete::~CConcrete()
virtual IAbstract::~IAbstract()
static void CConcrete::operator delete(void*)

delete ptrが実行されるdeleteと、仮想デストラクタ正しいが正しく呼び出されることに注意してくださいoperator delete()

注:これには、を使用するためにg++が必要です。__PRETTY_FUNCTION__

于 2012-10-26T17:03:16.110 に答える
0

これを試しましたか?プレースメントの新規作成/削除

于 2012-10-26T17:00:48.623 に答える