我一直在阅读有关重载新内容和删除(以及相关主题,例如放置新/删除)的内容。到目前为止,令我困惑的一件事是,operator delete的标准签名是(在类范围内):
void operator delete(void *rawMemory, std::size_t size) throw();
删除的方式如下:
MyClass* ptr = new MyClass;
delete ptr;
那么,delete ptr;
如何为大小提供第二个参数?另外,在这种情况下,我可以假设MyClass *被隐式转换为void *吗?
答案 0 :(得分:10)
new
和delete
运算符在类范围内重载,以优化特定类对象的分配。但是由于像Inheritance
这样的某些动物可能会出现特殊情况,这可能导致分配请求超过类大小本身,因为new
和delete
重载的目的是特殊调整对于大小为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的数量,并传递正确的大小。我完全不知道语言的这个古怪的角落是怎么来的。我无法想到编译器必须记住运行时值的语言的任何其他部分。