1

我在设计将使用自己的内存分配的适当类时遇到了一些麻烦。考虑一下:

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

我想做这样的事情:

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

问题是,我希望 CConcrete 的“新”使用内存分配器。另外,我希望“删除”使用适当的释放器。但是,new 和 delete 是静态函数,因此上面示例中的 delete 不会调用 CConcrete 的 delete(如果 delete 是虚拟的,它应该这样做)。

解决这个问题的一种方法是做这样的事情:

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

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

并在派生类中覆盖删除。但是这个解决方案非常难看,尤其是将 ptr 转换为 IAbstract*。

有没有更好的方法呢?

4

3 回答 3

0

你试过这个吗?放置新/删除

于 2012-10-26T17:00:48.623 回答
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

第一个有趣的事情是你不能转换你的 void 指针来调用任何成员函数。从技术上讲,它可以编译,但是在对象(或对象层次结构)被销毁(通过调用析构函数)之后调用运算符 delete。换句话说——你正在做的是UB,因为你试图访问一个被破坏的类的vtable。

另一件事是,只要您的析构函数是虚拟的,就会在类上调用适当的删除运算符。因此,无需在其之上使用额外的 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 回答