我找到了这个代码段
void* operator new(size_t nbytes)
{
if (nbytes == 0)
nbytes = 1; // so all alloc's get a distinct address
void* ans = malloc(nbytes + 4); // overallocate by 4 bytes
*(Pool**)ans = NULL; // use NULL in the global new
return (char*)ans + 4; // don't let users see the Pool*
}
此处https://isocpp.org/wiki/faq/dtors
我花了一个多小时现在试着了解*(Pool**)ans = NULL;
做了什么。
ans
是一个void指针,所以我假设它被强制转换为Pool
指针并且池设置为0.不是指针而是池本身,因为第三个*
在左边。但是Pool没有定义operator=
。
pointer**
显然是指向指针的指针......但在这种情况下,这对我没有意义,因为ans
是一个指针。
答案 0 :(得分:6)
这里使用Pool**
的唯一原因是语义正确,因为大概是“隐藏的”4字节头应该是指向Pool
的指针(所以ans
是一个指向Pool
的指针,*(Pool **)ans
的类型为Pool *
)。
除非您能够将*(Pool *)ans = NULL
分配给Pool
,否则无法执行NULL
,这可能无论如何都不是预期的效果。像*(int **)ans = NULL
或更荒谬的*(Pool ******)ans = NULL
这样的东西会产生相同的最终效果,但如果它最终是指向Pool
的指针,那么它在语义上会很奇怪。
在一天结束时,你最终会得到:
+---+---+---+---+- - -
| 0 | 0 | 0 | 0 | ... and nbytes more bytes
+---+---+---+---+- - -
^ ans ^ returned address (ans + 4)
前4个字节的目标是指向Pool
某处的指针。
考虑这一点的另一种方法是忽略整个nbytes
的事情,考虑这种一般模式:
void * ptr = malloc(sizeof(TYPE));
*(TYPE *)ptr = VALUE;
这应该是有道理的。现在,如果TYPE是Pool *
而VALUE是NULL
并且您将其纳入该模式,那么您可以看到它仍然有意义:
void * ptr = malloc(sizeof(Pool *));
*(Pool **)ptr = NULL;
然后在你的情况下你仍然基本上这样做,虽然你在最后分配一些额外的字节,但这与这里的类型无关。
顺便说一句,它可能会在这里(以及语义上懒惰)在所有地方硬编码4
,而不是sizeof(Pool *)
。
答案 1 :(得分:2)
不,它不是“强制转换为池指针”。演员是:
(Pool**)
这不是指向Pool
的指针。这是指向Pool
的指针。
所以,让我们假装ans
是Pool **
,因为它就是这样。在那种情况下:
*ans = NULL;
现在将ans
指向的指针设置为NULL
。不是Pool
类的一些制造实例。但指向它的指针。
但这里有一个更大的问题:
void* ans = malloc(nbytes + 4); // overallocate by 4 bytes
*(Pool**)ans = NULL; // use NULL in the global new
return (char*)ans + 4; // don't let users see the Pool*
这是非常古老的代码,仅当指针长度为4个字节时才会起作用。
在现代的64位平台上,有8个字节长的指针,整个事情都会失败......