为什么在这里使用static_cast而不是reinterpret_cast很重要? [英] Why is it important to use static_cast instead of reinterpret_cast here?

查看:167
本文介绍了为什么在这里使用static_cast而不是reinterpret_cast很重要?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在博客帖子的回复Raymond Chen



一位提问者指出

我相信C ++示例是不正确的,因为根据ISO C ++ 2003标准(10-3,第168页),派生类中的基类子对象的位置
是未指定的
,并且假设
基类的子对象总是在开始。 C
的例子在C ++中也很好,所以我坚持下去。


Raymond回应了


不做这个假设。这就是为什么重要的是
使用static_cast而不是reinterpret_cast。尝试它:添加一个虚拟
方法到OVERLAPPED(所以一个vtable在前面),并观察
编译器。 -Raymond]


我读过他的评论后可以猜到。使用static_cast在这个例子很好,但reinterpret_cast不是。因为reinterpret_cast不是转换vtable。我理解它是否正确?

虽然,如果我在那里使用C风格的演员(不reinterpret_cast),它也可能会出错?



我重读了更有效的C ++的演员解释,以了解。但是没有回答。

解决方案


使用static_cast在这个例子中,但reinterpret_cast不。因为reinterpret_cast不是转换vtable。


不,问题是 reinterpret_cast 完全忽视了继承。它将简单地返回相同的地址不变 1 。但是 static_cast 知道您正在执行向下转换:即从基础类转换为派生类。



让我们假装我们的实现提出了假设的 OVERLAPPEDEX 具有如下虚拟函数的类:

  + --- + ------------ + ------------------ + ------------- + 
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+ ------ + ------------ + ------------------ + ------ ------- +
^
|
ptr

我们给出的指针指向 OVERLAPPED 子对象。 reinterpret_cast 不会改变。它只会改变类型。显然,通过这个地址访问 OVERLAPPEDEX 类容易造成严重破坏,因为它的子对象的位置现在都错了!

 我们相信当我们通过指针访问OVERLAPPEDEX时我们有什么
+ ------ + ------------ + - ----------------- + ------------- +
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+ ------ + ------ + ----- + ------ + ----------- + ------ + ------ + ------ +
| vptr | OVERLAPPED | AssociatedClient | ClientState | < - 我们实际有什么
+ ------ + ------------ + ------------------ + ------------- +
^
|
ptr

static_cast 知道 OVERLAPPED * 转换为 OVERLAPPEDEX * 时必须调整地址,正确的事情:

  + ------ + ------------ +  - ---------------- + ------------- + 
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+ ------ + ------------ + ------------------ + ------ ------- +
^
|
ptr after static_cast







但是,如果我在那里使用C-Style转换(不是reinterpret_cast),它也可能会出错?


C风格的转换被定义为以下的第一个成功:


  1. const_cast

  2. static_cast

  3. static_cast c> b
  4. reinterpret_cast const_cast

可以看到,在 reinterpret_cast 之前尝试了 static_cast ,因此在这种情况下,一个C风格的演员也会做正确的事。






>不保证。对于 reinterpret_cast 上发生的事情几乎没有保证。我知道的所有实现将简单地给出相同的地址不变。


At a reply of a blog post of Raymond Chen,

A questioner pointed out

Raymond, I believe the C++ example is not correct since the position of the base class subobject in the derived class is unspecified according to ISO C++ 2003 Standard (10-3, page 168), and you assume that the base class subobject is always at the beginning. The C example would be fine in C++ too, so I'd stick with it.

Raymond replied

[The code does not make this assumption. That's why it's important to use static_cast instead of reinterpret_cast. Try it: Add a virtual method to OVERLAPPED (so a vtable goes in front) and observe what the compiler does. -Raymond]

I could guess after read his comments. Using static_cast is fine at the example but reinterpret_cast is not. Because reinterpret_cast is not convert vtable. Do I understand it rightly?
Though, if I use C-Style cast at there(not reinterpret_cast), could it also go wrong?

I re-read More Effective C++'s cast explanation to understand that. But there was no answer about that.

解决方案

Using static_cast is fine at the example but reinterpret_cast is not. Because reinterpret_cast is not convert vtable.

No, the problem is that the reinterpret_cast is completely oblivious about the inheritance. It will simply return the same address unchanged1. But static_cast knows that you're performing a downcast: i.e. casting from a base class to a derived class. Since it knows both types involved it adjusts the address accordingly, i.e., does the right thing.

Let's pretend our implementation lays out the hypothetical OVERLAPPEDEX class that has a virtual function like this:

+------+------------+------------------+-------------+
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+------+------------+------------------+-------------+
       ^
       |
      ptr

The pointer we're given points to the OVERLAPPED subobject. reinterpret_cast would not change that. It would only change the type. Obviously, accessing the OVERLAPPEDEX class through this address would easily wreak havoc, because the locations of its subobjects are all wrong now!

       what we believe we have when we access OVERLAPPEDEX through the pointer
       +------+------------+------------------+-------------+
       | vptr | OVERLAPPED | AssociatedClient | ClientState |
+------+------+-----+------+-----------+------+------+------+
| vptr | OVERLAPPED | AssociatedClient | ClientState | <- what we actually have
+------+------------+------------------+-------------+
       ^
       |
      ptr

static_cast knows that to convert a OVERLAPPED* to OVERLAPPEDEX* it must adjust the address, and does the right thing:

 +------+------------+------------------+-------------+
 | vptr | OVERLAPPED | AssociatedClient | ClientState |
 +------+------------+------------------+-------------+
 ^
 |
ptr after static_cast


Though, if I use C-Style cast at there(not reinterpret_cast), could it also go wrong?

A C-style cast is defined as the first one of the following that succeeds:

  1. const_cast
  2. static_cast
  3. static_cast, then const_cast
  4. reinterpret_cast
  5. reinterpret_cast, then const_cast

As you can see, a static_cast is tried before reinterpret_cast, so in this case, a C-style cast would also do the right thing.


More info


1Not guaranteed. There are very little guarantees about what happens on a reinterpret_cast. All implementations I know of will simply give out the same address unchanged.

这篇关于为什么在这里使用static_cast而不是reinterpret_cast很重要?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆