铸通过void*而不是使用reinterpret_cast
-
16-09-2019 - |
题
我在读一本书然后我发现 reinterpret_cast
不应将直接使用,而是铸造void*结合 static_cast
:
T1 * p1=...
void *pv=p1;
T2 * p2= static_cast<T2*>(pv);
代替:
T1 * p1=...
T2 * p2= reinterpret_cast<T2*>(p1);
然而,我不能找到一个解释为什么这是更好的比直接投。我会非常感激,如果有人能给我一个解释或点我到回答。
在此先感谢
p.s.我知道是什么 reinterpret_cast
使用,但是我从来没有看到是用这种方式
解决方案
为的类型对这种投被许可(例如如果 T1
是POD型和 T2
是 unsigned char
),方法 static_cast
是好定义的标准。
另一方面, reinterpret_cast
完全是执行情况定义的-唯一能保证你得到它是,你可以投一个指的类型的任何其他类型的指针,然后回来,你会得到原来的价值;而且,你可以投一个指类型的整型大,足以保持一个指价值的(这取决于执行,并且需要不存在),然后将它转换回来,你会得到原来的价值。
更具体来说,我只是报价的相关部分的标准,突出重要的部分:
5.2.10[expr.重新解释.放]:
执行的映射的reinterpret_cast是 执行情况定义的.[注:它可能会或可能不行,产生一个表示不同于原始价值。] ...指向一个对象可以明确地转变为一个指向一个目的不同的类型。) 除了这转右值的类型"的指针T1"类型"的指针T2"(其中T1和T2对象的类型和所在准要求的T2没有更严格的比T1)和回到其原有类型的收益的原始指针的价值, 结果这样的指针转换是不确定.
所以是这样的:
struct pod_t { int x; };
pod_t pod;
char* p = reinterpret_cast<char*>(&pod);
memset(p, 0, sizeof pod);
是有效的"未指定"。
解释为什么 static_cast
工作是一个比较棘手。这里是上述重写代码用 static_cast
我认为这是保证总是工作,旨在通过标准:
struct pod_t { int x; };
pod_t pod;
char* p = static_cast<char*>(static_cast<void*>(&pod));
memset(p, 0, sizeof pod);
再次,我要引用该段的标准一起,领导我得出结论认为,上述应该便携式:
3.9[基本的。类型]:
任何对象(其他基类子对象)的POD T型,是否对象包含一个有效的价值T类型,基础字节(1.7)的对象可以复制到一系列char或unsigned char。如果内容列char或unsigned char是复制回到对象,随后应将保持其原有的价值。
对象表示一个目的类型是T序列的N unsigned char 对象 采取的对象类型的T,在这里N等于sizeof(T)。
3.9.2[基本的。化合物]:
对象的简历资格(3.9.3)或cv-不合格的类型
void*
(针对无效),可以用来指向的对象不明的类型。一个void*
应能担任任何目的指针。 个人简历资格或cv-不合格(3.9.3)void*
应当有相同的表示和准要求个人简历资格或cv-不合格char*
.
3.10[基本的。lval]:
如果一个计划试图访问储存的价值的一个目通过一个左值的比其他的以下类型之一的行为是不确定):
- ...
- char或unsigned char type.
4.10[conv.ptr]:
Rvalue的类型"的指针的简历T,"这里是一个目类型,可以转换到右值的类型"的指针的简历无效。" 结果转换"的指针的简历T"的"指的简历无效的"点的存储位置在哪里的对象T类型的驻留,如果对象是大多数衍生物(1.8)T类型(即,不是一个基类子对象).
5.2.9[expr.静态的。放]:
反的任何标准的转换序列(第4条),比其他的左值到rvalue(4.1),array-topointer(4.2)、功能以指针(4.3)和布尔(4.12)转换,可以执行的明确使用static_cast.
[编辑] 另一方面,我们具有这种宝石:
9.2[类。mem]/17:
一个指荚结构目的,适当地转换成使用reinterpret_cast,其初始成员(或者如果该成员是一位域,然后向部在其驻留),反之亦然。[注:有可能 因此 被不知名的填补内荚结构的对象,而不是在其开始,作为必要的,以实现适当的应对准。]
这似乎意味着 reinterpret_cast
之间的指针以某种方式意味着"相同的地址"。去图。
其他提示
有没有丝毫怀疑意图是这两种形式是有严格规定,但措辞未能捕获
这两种形式的实际运作。
reinterpret_cast
是更加明确的意图,应当优选的。
真正的原因是这样是因为,因为构件的指针的C ++如何定义继承和
使用C,指针是非常简单,只是一个地址,因为它应该是。在C ++中它必须是因为它的一些功能更加复杂。
会员指针真正的偏移量为一类,所以铸造他们总是用C风格的灾难。
如果您有多重继承也有一些具体的地方的两个虚拟对象,这也是对C风格的一场灾难。这是多重继承,导致所有的问题,但情况,所以你不应该永远无论如何要使用这一点。
真的希望你永远在第一时间使用这些案件。另外,如果你是铸造了很多这是另一个迹象,你在你的设计搞乱了。
我最终铸件的唯一时间是在区域C ++决定的原语是不一样的,但很明显在那里他们必须如此。对于实际的对象,你想投的东西,任何时候开始质疑你的设计,因为你应该是“编程接口”的大部分时间。当然,你不能改变第三方API是如何工作的第三次,所以你并不总是有太多的选择。