static_cast 安全性
AFAIK,对于指针/引用 static_cast,如果此时编译器看不到类定义,则 static_cast
的行为将类似于 reinterpret_cast
。
为什么 static_cast
对于指针/引用不安全,而对于数值则安全?
AFAIK, for pointers/references static_cast, if a class definition is not visible to compiler at this point, then static_cast
will be behave like reinterpret_cast
.
Why is static_cast
unsafe for pointers/references and is safe for numeric values?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
简而言之,因为多重继承。
in long:
输出:
请注意,为了正确转换为 B*,static_cast 必须更改指针值。如果编译器没有 C 的类定义,那么它就不会知道 B 是基类,并且它当然不会知道要应用什么偏移量。
但在没有定义可见的情况下,static_cast 的行为不像reinterpret_cast,它是被禁止的:
一个普通的 C 风格的强制转换,
(B*)(&c)
会按照你所说的去做: struct C的定义是可见的,表明B是基类,那么它与static_cast相同。如果类型仅是前向声明的,那么它与reinterpret_cast 相同。这是因为它被设计为与 C 兼容,这意味着它必须在 C 中可能的情况下执行 C 所做的事情。static_cast 始终知道如何处理内置类型,这就是内置的真正含义。它可以将int转换为float等等。这就是为什么它对于数字类型总是安全的,但它不能转换指针,除非(a)它知道它们指向什么,并且(b)所指向的类型之间存在正确的关系。因此它可以将
int
转换为float
,但不能将int*
转换为float*
。正如 AndreyT 所说,有一种方法可以不安全地使用
static_cast
,编译器可能不会拯救你,因为代码是合法的:其中之一
static_cast
能做的就是“向下转型”一个指向派生类的指针(在本例中,C 是 A 的派生类)。但如果引用对象实际上不是派生类的,那么你就注定失败了。dynamic_cast
将在运行时执行检查,但对于我的示例类 C,您不能使用dynamic_cast
,因为 A 没有虚函数。您也可以使用
static_cast
与void*
进行类似的不安全操作。In short, because of multiple inheritance.
In long:
Output:
Note that in order to convert correctly to B*, static_cast has to change the pointer value. If the compiler didn't have the class definition for C, then it wouldn't know that B was a base class, and it certainly wouldn't know what offset to apply.
But in that situation where no definition is visible, static_cast doesn't behave like reinterpret_cast, it's forbidden:
A plain C-style cast,
(B*)(&c)
does what you say: if the definition of struct C is visible, showing that B is a base class, then it's the same as a static_cast. If the types are only forward-declared, then it's the same as a reinterpret_cast. This is because it's designed to be compatible with C, meaning that it has to do what C does in cases which are possible in C.static_cast always knows what to do for built-in types, that's really what built-in means. It can convert int to float, and so on. So that's why it's always safe for numeric types, but it can't convert pointers unless (a) it knows what they point to, and (b) there is the right kind of relationship between the pointed-to types. Hence it can convert
int
tofloat
, but notint*
tofloat*
.As AndreyT says, there is a way that you can use
static_cast
unsafely, and the compiler probably won't save you, because the code is legal:One of the things
static_cast
can do is "downcast" a pointer to a derived class (in this case, C is a derived class of A). But if the referand is not actually of the derived class, you're doomed. Adynamic_cast
would perform a check at runtime, but for my example class C you can't use adynamic_cast
, because A has no virtual functions.You can similarly do unsafe things with
static_cast
to and fromvoid*
.不,你的“据我所知”是不正确的。
static_cast
永远不会表现得像reinterpret_cast
(除非,当您转换为void *
时,尽管这种转换通常不应该由执行代码>reinterpret_cast
)。首先,当
static_cast
用于指针或引用转换时,static_cast
的规范明确要求类型之间存在一定的关系(并且static_cast已知)。对于类类型,它们应通过继承相关,正如
static_cast
所感知的那样。如果没有static_cast
点完全定义两种类型,就不可能满足该要求。因此,如果定义在 static_cast 处不可见,则代码将无法编译。用示例来说明上述内容:可以[冗余地]使用
static_cast
来执行对象指针向上转换。 该代码仅当以下代码可编译时,
才可编译,并且要编译这两种类型的定义必须可见。
此外,
static_cast
可用于执行对象指针向下转换。 该代码仅当以下代码可编译时,
才可编译,并且同样,要编译这两种类型的定义必须可见。
因此,您根本无法将
static_cast
与未定义的类型一起使用。如果您的编译器允许这样做,那么这就是您的编译器中的错误。由于完全不同的原因,
static_cast
对于指针/引用来说可能是不安全的。static_cast
可以对对象指针/引用类型执行分层向下转型,而无需检查对象的实际动态类型。static_cast
还可以对方法指针类型执行分层向上转换。如果不小心使用这些未经检查的强制转换的结果可能会导致未定义的行为。其次,当
static_cast
与算术类型一起使用时,语义完全不同,与上述无关。它仅执行算术类型转换。只要它们符合您的意图,它们总是完全安全的(除了范围问题)。事实上,避免使用
static_cast
进行算术转换并使用旧的 C 风格转换可能是一种很好的编程风格,只是为了在源代码中提供始终安全的算术转换和潜在的转换之间的明确区别。 -不安全的分层指针/引用转换。No, your "AFAIK" is incorrect.
static_cast
never behaves asreinterpret_cast
(except, maybe when you convert tovoid *
, although this conversion is not normally supposed to be carried out byreinterpret_cast
).Firstly, when
static_cast
is used for pointer or reference conversions, the specification of thestatic_cast
explicitly requires a certain relationship to exist between the types (and be known tostatic_cast
). For class types, they shall be related by inheritance, as perceived bystatic_cast
. It is not possible to satisfy that requirement without having both types completely defined by the point ofstatic_cast
. So, if the definition(s) is(are) not visible at the point ofstatic_cast
, the code simply will not compile.To illustrate the above with examples:
static_cast
can be used [redundantly] to perform object pointer upcasts. The codeis only compilable when the following code is compilable
and for this to compile the definition of both types have to be visible.
Also,
static_cast
can be used to perform object pointer downcasts. The codeis only compilable when the following code is compilable
and, again, for this to compile the definition of both types have to be visible.
So, you simply won't be able to use
static_cast
with undefined types. If your compiler allows that, it is a bug in your compiler.static_cast
can be unsafe for pointers/references for a completely different reason.static_cast
can perform hierarchical downcasts for object pointer/reference types without checking the actual dynamic type of the object.static_cast
can also perform hierarchical upcasts for method pointer types. Using the results of these unchecked casts can lead to undefined behavior, if done without caution.Secondly, when
static_cast
is used with arithmetic types, the semantics is totally different andhas nothing to do with the above. It just performs arithmetic type conversions. They are always perfectly safe (aside form the range issues), as long as they fit your intent. In fact, it might be a good programming style to avoid
static_cast
for arithmetic conversions and use old C-style casts instead, just to provide a clear differentiation in the source code between always-safe arithmetic casts and potentially-unsafe hierarchical pointer/reference casts.