为什么不能static_cast双虚空指针?

Why can't static_cast a double void pointer?

本文关键字:空指针 cast 不能 static 为什么      更新时间:2023-10-16

考虑以下代码段:

void **v_dptr(nullptr);
int  **i_dptr = static_cast<int**>(v_dptr);

上面的示例产生以下编译错误:

static_cast from 'void **' to 'int **' is not allowed

现场演示

我知道将void指针转换为任何其他指针类型的正确方法是使用 static_cast .但是,不能将双void指针static_cast到其他类型的另一个双指针。

问:

  1. 为什么我们不能static_castvoid指针?
  2. 投双void指针的正确方法是什么?

当你有一个void*并将其转换为int*时,可能会也可能不会有一些数学/宽度调整来创建正确类型的实例,static_cast<>将准备这样做。 当您只有一个指向void*的指针并且想要一个指向int*的指针时,static_cast<>对指向的void*对象没有写入访问权限;调整它以确保它是一个有效的int*这样static_cast<>可以成功并返回一个真正可用于访问有效int*的指针是不自由的。 虽然在某些架构上这可能无关紧要,但如果标准允许这样做,那么代码在移植时可能会中断。 (请记住,期望static_cast<>为它使用static_cast<int*>(the_void_ptr)初始化的某个地方int*安排一些额外的内存是不合理的 - 这不仅会产生意外的开销,而且它需要在线程特定的内存中或动态分配并以某种方式释放,并且实际上最终比较指针值的所有代码都会中断。

如果你想强迫这个问题,并向编译器承诺两种类型的宽度是相同的,不需要数学调整等 - 那么你可以使用reinterpret_cast<>并操纵它,清楚地表明你正在接受未定义行为的风险。

void*的特殊之处在于它可以指向任何东西。它是"指向未指定类型的指针"。因此,对于某种类型的T,从void*T*的转换是一种"正常"操作,static_cast可以支持的操作。实际上,这样的转换说:"指针不知道它指向什么,但我知道它:它指向一个T

void**在这种方式上并不特别。它只能指向一件事,指向void*。将void**转换为int**会说一些不同的东西:"指针声称它指向void*,但我想将其视为指向int*的指针。如果你想把一件事当作另一件事,你想重新解释原作——所以使用 reinterpret_cast .

我相信

这是一个XY问题。根据情况,可以在没有reinterpret_cast的情况下解决。如果您知道void**指针实际上指向指向 int 的指针,则可以安全地执行此操作:

int* iptr = static_cast<int*>(*v_dptr);

除非你真的需要在代码中int**。如果需要,您可以执行以下操作:

int** i_dptr = &iptr;

但请注意,它会指向一个局部变量iptr当超出范围时,该变量将被销毁。

Q1 有很好的答案,Q2 的答案很大程度上取决于意图。如果void **v_dptr旨在成为指向"泛型"void*的指针,您知道该实际上是一个int*并且您希望相应地强制转换,则以下内容可能是您想要的:

int *i_ptr = static_cast<int*>(*v_dptr);
int **i_dptr = &i_ptr;

static_cast可以执行任何隐式转换的反向操作。

有一个隐式转换int*void*;它只不过丢失了关于指向对象的类型的信息。

没有隐式转换int**void**。如果允许,它将重新解释对象指针,即将int*重新解释void*。在一些旧体系结构上,int*不一定具有像void*(或char*,对齐要求最少的指针类型(那样具有那么大的值表示。

重新解释需要reinterpret_cast

恕我直言,通常使用reinterpret_cast进行与void*的转换是个好主意,因为这会向读者传达意图。然而,我记得萨特和亚历山德雷斯库建议使用static_cast,大概是由于C++03缺乏正式保证。我还记得,这个纯粹的形式问题在第 11 C++ 中得到了解决。