在他的“C ++编程语言”(第4版)一书中,stroustroup提到了全球运营商new&通过使用以下签名编写全局函数可以重载delete:
void* operator new(size_t); // use for individual object
void* operator new[](size_t); // use for array
void operator delete(void*, size_t); // use for individual object
void operator delete[](void*, size_t); // use for array
注意:为删除传递size_t参数以确定正确的对象大小,特别是在删除基指针指向的派生对象时(base需要虚拟dtor以便传递正确的大小)。
我试图重载单个对象的全局版本。操作员新的工作正常。使用上述签名的操作员删除工作正常,但不会调用删除。如果我更改删除签名以便它只需要一个void *,它就会被调用。可能是什么问题:
这是代码:
void * operator new (size_t size)
{
cout << "My operator new called\n";
auto p = malloc(size);
return p;
}
void operator delete (void * ptr, size_t size) // Removing size_t parameter makes it work
{
cout << "My operator delete called\n";
free(ptr);
}
奇怪的是,如果我让操作符删除一个类的成员以便它只为该类重载,那么删除签名(使用size_t且没有size_t)似乎都有效!
在删除中传递size_t参数似乎是合乎逻辑的,如我在上面提到的注释中所解释的那样。但是这种行为可能是什么原因呢?我正在使用VS2013来测试这些示例。
答案 0 :(得分:1)
来自C ++ 1y草案:
5.3.5删除
[expr.delete]
[...]
11执行delete-expression时,应调用所选的释放函数,并将要回收的存储块的地址作为其第一个参数,并且(如果使用双参数解除分配函数)将块的大小作为其第二个论点.83脚注83)如果要删除的对象的静态类型是完整的并且与动态类型不同,则析构函数不是 虚拟,大小可能不正确,但是这种情况已经未定义,如上所述。
17.6.4.6替换函数
[replacement.functions]
1第18至30条和附录D描述了C ++标准库定义的众多函数的行为。但是,在某些情况下,某些功能描述也适用于程序中定义的替换功能(17.3) 2 C ++程序可以为标题
<new>
(3.7.4,18.6)中声明的12个动态内存分配函数签名中的任何一个提供定义:operator new(std::size_t) operator new(std::size_t, const std::nothrow_t&) operator new[](std::size_t) operator new[](std::size_t, const std::nothrow_t&) perator delete(void*) operator delete(void*, const std::nothrow_t&) operator delete[](void*) operator delete[](void*, const std::nothrow_t&)
由我注意:接下来的四个是C ++ 1y中的新内容
operator delete(void*, std::size_t) operator delete(void*, std::size_t, const std::nothrow_t&) operator delete[](void*, std::size_t) operator delete[](void*, std::size_t, const std::nothrow_t&)
3使用程序的定义而不是实现提供的默认版本(18.6)。这种替换发生在程序启动之前(3.2,3.6)。程序的定义不应指定为内联。无需诊断。
另请参阅在C ++ 1y中引入大小释放的提议:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3536.html
答案 1 :(得分:1)
在C ++ 11中,非成员void operator delete(void*, size_t)
是&#34;展示位置释放,附加参数&#34;。它对应于具有附加参数的放置分配(如果您定义了一个):void *operator new(size_t, size_t)
。
根据3.7.4.2澄清这一点,T::operator delete(void*, size_t)
是通常的释放函数,但是N3337并没有说::operator delete(void *, size_t)
是通常的释放函数;事实上,::operator delete
的签名不会出现在文档的任何位置。具体来说,17.6.4.6没有在全球版本中列出它。
在C ++ 1y中,::operator delete(void*, size_t)
是通常的解除分配函数(即非放置)。在我看来,这是C ++ 11和C ++之间的一个重大变化。
根据N3797,在C ++中,如果你替换operator delete(void *)
,那么你也必须替换operator delete(void *, size_t)
,反之亦然。 (否则,据推测,该程序是不正确的。)
同样根据N3797,可以调用这两个函数中的任何一个来解除分配,但是我没有看到在哪种情况下调用哪个函数的明确规范。
注意:重载是错误的术语;当您定义通常的分配运算符时,它替换标准库版本。