为什么operator delete的签名有两个参数?

时间:2011-10-19 15:57:58

标签: c++ memory

我一直在阅读有关重载新内容和删除(以及相关主题,例如放置新/删除)的内容。到目前为止,令我困惑的一件事是,operator delete的标准签名是(在类范围内):

void operator delete(void *rawMemory, std::size_t size) throw();

删除的方式如下:

MyClass* ptr = new MyClass;
delete ptr;

那么,delete ptr;如何为大小提供第二个参数?另外,在这种情况下,我可以假设MyClass *被隐式转换为void *吗?

3 个答案:

答案 0 :(得分:10)

简答:

newdelete运算符在类范围内重载,以优化特定类对象的分配。但是由于像Inheritance这样的某些动物可能会出现特殊情况,这可能导致分配请求超过类大小本身,因为newdelete重载的目的是特殊调整对于大小为sizeof(Base)但不大或小的对象,这些重载运算符应将所有其他wrong sized内存请求转发给::operator new::operator delete,以便能够执行此操作, size参数需要作为参数传递。

长答案:

考虑特殊场景:

class Base 
{
    public:
        static void * operator new(std::size_t size) throw(std::bad_alloc);
};



class Derived: public Base 
{
   //Derived doesn't declare operator new
};                                  

int main()
{
    // This calls Base::operator new!
    Derived *p = new Derived;                 

    return 0;
}

在上面的示例中,由于继承,派生类Derived继承了Base类的new运算符。这使得在基类中调用operator new可以为派生类的对象分配内存。我们的操作员new处理这种情况的最佳方法是将请求“错误”内存量的此类调用转移到标准运算符new,如下所示:

void * Base::operator new(std::size_t size) throw(std::bad_alloc)
{

    if (size != sizeof(Base))          // if size is "wrong," i.e != sizeof Base class
    {
         return ::operator new(size);  // let std::new handle this request
    }
    else
    {
         //Our implementation
    }
}

在重载delete运算符时,还必须确保由于特定于类的运算符将“错误”大小的请求转发给::operator new,因此必须将“错误大小”的删除请求转发到: :operator delete,因为原始运算符保证以标准兼容的方式处理这些请求。

所以自定义delete运算符将是这样的:

class Base 
{                            
   public:                                 
      //Same as before
      static void * operator new(std::size_t size) throw(std::bad_alloc);       
      //delete declaration
      static void operator delete(void *rawMemory, std::size_t size) throw();      

     void Base::operator delete(void *rawMemory, std::size_t size) throw()
     {
         if (rawMemory == 0) 
         {
              return;                            // No-Op is null pointer
         }

         if (size != sizeof(Base)) 
         {           
             // if size is "wrong,"
             ::operator delete(rawMemory);      //delegate to std::delete
             return;                            
         }
        //If we reach here means we have correct sized pointer for deallocation
        //deallocate the memory pointed to by rawMemory;

        return;
     }
};

进一步阅读:
以下C ++ - Faq条目讨论了以标准兼容的方式重载new和delete,并且可能对您有好处:

<强> How should i write iso c++ standard conformant custom new and delete operators?

答案 1 :(得分:7)

  

那么,如何删除ptr;提供尺寸的第二个参数?

如果指针类型是具有虚拟析构函数的类类型,则来自有关对象类型的动态信息。如果它没有虚拟析构函数并且指针类型匹配指针类型 - 来自编译时间信息有关类型大小。否则delete ptr是未定义的行为。

答案 2 :(得分:0)

当您致电delete时,记住要释放的大小是编译器的工作。对于delete ptr;,它将通过sizeof(MyClass),对于delete[] ptr;,它必须记住数组中MyClass的数量,并传递正确的大小。我完全不知道语言的这个古怪的角落是怎么来的。我无法想到编译器必须记住运行时值的语言的任何其他部分。