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

Joh*_*0te 9 c++ memory

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

void operator delete(void *rawMemory, std::size_t size) throw();
Run Code Online (Sandbox Code Playgroud)

删除的方式如下:

MyClass* ptr = new MyClass;
delete ptr;
Run Code Online (Sandbox Code Playgroud)

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

Alo*_*ave 10

简答:

new并且delete在类范围内重载运算符以优化特定类对象的分配.但是由于某些特殊情况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;
}
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,由于继承,派生类Derived继承了该类的new运算符Base.这使得在基类中调用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
    }
}
Run Code Online (Sandbox Code Playgroud)

在重载delete运算符时,One还必须确保由于特定于类的运算符新转发"错误"大小的请求,因此::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;
     }
};
Run Code Online (Sandbox Code Playgroud)

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

我应该如何编写iso c ++标准符合自定义新的和删除运算符?


Tad*_*pec 7

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

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