C++ 我应该使用它还是静态_cast<;无效*>;然后静态_cast<;myType*>;为了避免重新解释?

C++ 我应该使用它还是静态_cast<;无效*>;然后静态_cast<;myType*>;为了避免重新解释?,c++,casting,reinterpret-cast,static-cast,C++,Casting,Reinterpret Cast,Static Cast,我曾看到有人建议使用static\u cast(static\u cast(p))而不是重新解释cast 我不明白为什么这样更好,有人能解释一下吗 为了便于讨论,这里有一个需要重新解释的示例场景: DWORD lpNumberOfBytes; ULONG_PTR lpCompletionKey; LPOVERLAPPED lpOverlapped; GetQueuedCompletionStatus(myHandle, &lpNumberOfBytes, &lpCompletio

我曾看到有人建议使用
static\u cast(static\u cast(p))
而不是重新解释cast

我不明白为什么这样更好,有人能解释一下吗

为了便于讨论,这里有一个需要重新解释的示例场景:

DWORD lpNumberOfBytes;
ULONG_PTR lpCompletionKey;
LPOVERLAPPED lpOverlapped;
GetQueuedCompletionStatus(myHandle, &lpNumberOfBytes, &lpCompletionKey, &lpOverlapped, 0);
if(lpCompletionKey == myCustomHandlerKey){
    auto myObject = reinterpret_cast<MyObject*>(lpOverlapped);  //i know this is really a MyObject
}
DWORD lpNumberOfBytes;
ULONG_PTR lpCompletionKey;
lp重叠lp重叠;
GetQueuedCompletionStatus(myHandle,&lpNumberOfBytes,&lpCompletionKey,&lpOverlapped,0);
如果(lpCompletionKey==myCustomHandlerKey){
auto myObject=reinterpret_cast(lpOverlapped);//我知道这确实是一个myObject
}
这就是我听到的建议:

auto myObject = static_cast<MyObject*>(static_cast<void*>(lpOverlapped));
auto myObject=static_cast(static_cast(lpOverlapped));

编辑:我最初是从评论部分开始提问的,“asdf”建议在此处使用静态转换而不是重新解释转换,但回想起来,我的问题来自于此并不相关。

§5.2.10描述了
重新解释转换
可以执行的法律映射,并指定“无法执行其他转换”

与您的示例相关的转换为/7:

指向对象的指针可以显式转换为指向不同对象类型的指针。当类型为“指针指向
T1
”的prvalue
v
转换为类型为“指针指向cv
T2
”时,结果是
static\u cast(static\u cast(v))
如果
T1
T2
都是标准布局类型,
T2
的对齐要求并不比
T1
的对齐要求更严格。
[强调]

任何其他指向对象类型的指针的转换结果为“未指定”。1

这是
reinterpret\u cast
危险的两个原因之一:它的转换只针对指向对象类型的指针子集定义良好,编译器通常不提供关于意外误用的诊断

第二个原因是编译器甚至不会首先检查您尝试执行的映射是否合法,以及要执行的许多(语义完全不同)映射中的哪一个

最好是明确地告诉编译器(和读者)也就是说,asdf的评论并不完全正确,因为并非所有您可能希望通过
reinterpret\u cast
执行的转换都等同于使用
static\u cast
然后对目标类型执行
static\u cast



1旁白:简而言之(稍微简化),a是一个类型(或类型数组)它没有虚拟函数或混合成员可见性,并且它的所有成员和基也是标准布局。类型的类型限制了它可能位于的内存中的地址。例如,许多机器要求将双精度对齐到可被8整除的地址。

asdf
对此进行了解释很好,即使在链接的帖子中简洁地说

因为编译器不知道CustomImage是从 这是程序中的一点

就我个人而言,我不会费心从msdn下载垃圾,只是为了深入研究并回答这个问题。毕竟这是一个编码挑战,你应该弄清楚它

<>我在C++中的铸造规则是:

  • 使用C++样式转换<代码> XXXCAST 而不是C风格<代码>(T*)< /C> >,为显式优于隐式。
  • 只有在你真正想表达的时候才使用reinterpret cast
  • 如果您确实使用了“重新解释强制转换”,请确保强制转换/取消强制转换是精确的镜像,例如:
  • T*obj=。。。;
    void*tmp=重新解释铸造对象;
    T*ref=reinterpret\u cast tmp;//T*obj-->T*ref
    

    在这里,您必须确保
    obj
    ref
    是相同的精确类型,包括常量限定符、类派生、对齐、内存类型(嵌入式),绝对是你能想到的任何东西。

    reinterpret\u cast几乎总是实现定义的,发生的事情并不总是保证可移植的。@Plasmah这有点误导。
    reinterpret\u cast
    有非常好的定义语义,它们只是非常有限。但在这种情况下,语义似乎被覆盖了(根据OP的声明,
    lpOverlapped
    ),我在没有看代码的情况下这么说。但是阅读asdf的注释是完全不同的情况。当您从一个指针类型强制转换到另一个指针类型时,
    reinterpret\u cast
    是根据
    静态强制转换(静态强制转换(p))来指定的
    在C++11中。它们都是相同的。另一方面,如果您想确保转换是安全的,可以使用,然后使用
    指针强制转换(lpOverlapped)
    +1用于引用标准和解释最重要的部分…如果你这样做了,我会给+2用于列出和解释所有的个人要求,如果我可以的话。你看,甚至我在我的回答中忘记了对齐。双
    静态\u cast
    是在定义reinterptret和标识双cast的情况之外定义的吗?@Yakk我不太清楚你的意思,但如果我理解正确的话,双
    static\u cast
    via
    void*`比
    reinterpret\u cast
    更具限制性,而不是更一般性。这就是为什么选择它的原因:它的语义因此更清晰。@Konradulph
    reinterpret\u cast
    说“如果是条件,那么它相当于
    static\u cast(X))
    ”现在,如果其中一个条件,或者
    X
    T*
    (即使条件不成立),那么如果显式写出,该双-
    static\u cast
    ,则是有效的.还有其他情况下,双静态强制转换会导致定义的行为吗?@Yakk说实话,我不知道。在阅读之前
    T* obj = ...;
    void* tmp = reinterpret_cast<void*> obj;
    T* ref = reinterpret_cast<T*> tmp;  // T* obj --> T* ref