具有自己的内存分配的类的设计

时间:2012-10-26 16:52:19

标签: c++ allocation

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

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

我想做这样的事情:

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

问题是,我希望CConcrete的“新”使用内存分配器。另外,我希望“删除”使用propriate deallocator。但是,new和delete是静态函数,所以上面的例子中的delete不会调用CConcrete的删除(如果删除是虚拟的话应该这样做。)

解决这个问题的一种方法是制作这样的东西:

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

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

并覆盖派生类中的Delete。但是这个解决方案非常难看,特别是将ptr转换为IAbstract *。

有没有更好的方法呢?

3 个答案:

答案 0 :(得分:0)

你试过这个吗? Placement new/delete

答案 1 :(得分: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()

注意:由于使用__PRETTY_FUNCTION__

,这需要g ++

答案 2 :(得分:0)

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

另一件事是,只要析构函数是虚拟的,就会在类上调用适当的delete运算符。因此,没有必要使用额外的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。