考虑以下代码:
void **v_dptr(nullptr);
int **i_dptr = static_cast<int**>(v_dptr);
上面的示例产生以下编译错误:
static_cast from 'void **' to 'int **' is not allowed
我知道将void
指针强制转换为任何其他指针类型的正确方法是使用static_cast
。但是,您不能static_cast
指向其他类型的另一个双指针的双void
指针。
static_cast
使用void
指针?void
指针的正确方法是什么?答案 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中修复了纯正式的问题。