为什么不能static_cast一个双void指针?

时间:2014-10-09 11:35:28

标签: c++ pointers void-pointers

考虑以下代码:

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

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

  

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

LIVE DEMO

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

问:

  1. 为什么我们可以static_cast使用void指针?
  2. 投射双void指针的正确方法是什么?

5 个答案:

答案 0 :(得分:11)

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

如果你想强迫这件事并承诺编译器两种类型的宽度是相同的,并且不需要进行数学调整等等 - 那么你可以使用reinterpret_cast<>并对它进行调整,明确你'接受未定义行为的风险。

答案 1 :(得分:7)

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

void**以这种方式并不特别。它只能指向void*一件事。将void**转换为int**会说出不同的内容:“指针声称它指向void*,但我想将其视为指向int*的指针。”如果你想把一件事当作另一件事,你想重新解释原作 - 所以使用reinterpret_cast

答案 2 :(得分:2)

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

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

除非您的代码中确实需要int**。如果您需要,您可以这样做:

int** i_dptr = &iptr;

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

答案 3 :(得分:2)

Q1有很好的答案,Q2的答案在很大程度上取决于意图。如果void **v_dptr旨在成为指向&#34;泛型&#34;的指针。您知道的void*实际上是int*并且您想要相应地投射,以下可能是您想要的:

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

答案 4 :(得分:1)

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

隐式转化int*void*;它不会丢失有关指向对象类型的信息。

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

重新解释需要reinterpret_cast

恕我直言,一般情况下使用reinterpret_cast 进行void*的转换是个好主意,因为这会向读者传达意图。但是,我记得Sutter和Alexandrescu推荐使用static_cast,可能是因为C ++ 03缺乏正式保证。我还记得,在C ++ 11中修复了纯正式的问题。