将指针转换为指针.指针

casting pointer to pointer... to pointer?

本文关键字:指针 转换      更新时间:2023-10-16

我找到了这个片段

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是一个空指针,所以我假设它被转换为Pool指针,池被设置为0。不是指针,而是池本身,因为左边的第三个*。但是Pool没有定义operator=

声明中的

pointer**显然是指向指针的指针…但是在这种情况下,这对我来说没有意义,因为ans是一个单指针。

这里使用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 *)可能会带来麻烦(并且在语义上也是懒惰的)。

不,它不是"转换为池指针"。强制类型是:

(Pool**)

这不是指向Pool的指针。这是一个指向Pool的指针。

那么,现在让我们假设ansPool **,因为它就是这样。在这种情况下:

*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字节长的指针,这整个事情将惨败…