【问题标题】:casting pointer to pointer... to pointer?将指针转换为指针...指针?
【发布时间】:2016-09-10 22:57:32
【问题描述】:

我找到了这个sn-p

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 是单个指针。

【问题讨论】:

    标签: c++ pointers casting


    【解决方案1】:

    在这里使用Pool** 的唯一原因是语义正确性,因为大概“隐藏”的 4 字节标头应该是指向 Pool 的指针(所以 ans 是指向指向Pool,而*(Pool **)ans 的类型为Pool *)。

    除非您能够将Pool 分配给NULL,否则您无法执行*(Pool *)ans = 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 *) 可能会在这里自找麻烦(而且在语义上也是懒惰的)。

    【讨论】:

      【解决方案2】:

      不,它不是“强制转换为池指针”。演员是:

      (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 字节长的指针,这整个事情将惨遭失败......

      【讨论】:

      • 这不是“奇数”。该代码假定所有指向对象的指针都是 4 字节(通常是 32 位)并关联对齐。将4 重写为sizeof(Pool *) 可能会更好。或者完全删除它——偏移量更像是一个肮脏的把戏(程序员试图添加一个伪安全措施),并没有实现太多的实际用途。 (如果删除它,还要修改其他直接操作Pool的函数,因为它们也会使用偏移量)。
      • @Peter Sam 输入的是“OLD”而不是“ODD”。
      猜你喜欢
      • 2012-10-24
      • 2017-02-12
      • 1970-01-01
      • 2021-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多