这个 static_cast 到底有什么不安全的地方?
Exactly what is unsafe about this static_cast?
我写了一个不安全的小例子static_cast
:
#include <iostream>
class A
{
public:
virtual int getA(){ return 1; }
};
class B : public A
{
public:
virtual int getA() { return 2; }
int getB() { return 3; }
};
int main()
{
A a;
B b;
B* b1 = static_cast<B*>(&a);
std::cout << "b.getA(): " << b.getA() << std::endl;
std::cout << "b.getB(): " << b.getB() << std::endl;
std::cout << "b1->getA(): " << b1->getA() << std::endl;
std::cout << "b1->getB(): " << b1->getB() << std::endl;
}
输出:
b.getA(): 2
b.getB(): 3
b1->getA(): 1
b1->getB(): 3
我认为它不安全,因为我在创建 b1
时从未 运行 B
构造函数,尽管将其作为 B
对象访问。显然,输出的差异表明 b1
没有指向 B
对象,而是指向 A
对象,正如预期的那样。
这还有哪些方面不安全。像这样执行 static_cast
是否涉及未定义的行为?否则,访问 getA
或 getB
方法可能是未定义的行为吗?
还有什么吗? (我不关心丢失的虚拟析构函数,在这个例子中我不关心)
cpp.sh 可用代码:http://cpp.sh/7sxtz
在执行 static_cast
之后访问 *b1
的值是未定义的行为:
[basic.lval]/10 (N3337):
If a program attempts to access the stored value of an object through a glvalue of other than one of the
following types the behavior is undefined
— the dynamic type of the object,
— a cv-qualified version of the dynamic type of the object,
— a type similar (as defined in 4.4) to the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type
of the object,
— an aggregate or union type that includes one of the aforementioned types among its elements or non-
static data members (including, recursively, an element or non-static data member of a subaggregate
or contained union),
— a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
— a char or unsigned char type.
static_cast<B *>(&a)
导致未定义的行为。
C++14 [expr.static.cast]/11:
[...] If the prvalue of type “pointer to cv1 B
” points to a B
that is actually a subobject of an object of type D
, the resulting pointer points to the enclosing object of type D
. Otherwise, the behavior is undefined.
我写了一个不安全的小例子static_cast
:
#include <iostream>
class A
{
public:
virtual int getA(){ return 1; }
};
class B : public A
{
public:
virtual int getA() { return 2; }
int getB() { return 3; }
};
int main()
{
A a;
B b;
B* b1 = static_cast<B*>(&a);
std::cout << "b.getA(): " << b.getA() << std::endl;
std::cout << "b.getB(): " << b.getB() << std::endl;
std::cout << "b1->getA(): " << b1->getA() << std::endl;
std::cout << "b1->getB(): " << b1->getB() << std::endl;
}
输出:
b.getA(): 2
b.getB(): 3
b1->getA(): 1
b1->getB(): 3
我认为它不安全,因为我在创建 b1
时从未 运行 B
构造函数,尽管将其作为 B
对象访问。显然,输出的差异表明 b1
没有指向 B
对象,而是指向 A
对象,正如预期的那样。
这还有哪些方面不安全。像这样执行 static_cast
是否涉及未定义的行为?否则,访问 getA
或 getB
方法可能是未定义的行为吗?
还有什么吗? (我不关心丢失的虚拟析构函数,在这个例子中我不关心)
cpp.sh 可用代码:http://cpp.sh/7sxtz
在执行 static_cast
之后访问 *b1
的值是未定义的行为:
[basic.lval]/10 (N3337):
If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined— the dynamic type of the object,
— a cv-qualified version of the dynamic type of the object,
— a type similar (as defined in 4.4) to the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,
— an aggregate or union type that includes one of the aforementioned types among its elements or non- static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),
— a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
— a char or unsigned char type.
static_cast<B *>(&a)
导致未定义的行为。
C++14 [expr.static.cast]/11:
[...] If the prvalue of type “pointer to cv1
B
” points to aB
that is actually a subobject of an object of typeD
, the resulting pointer points to the enclosing object of typeD
. Otherwise, the behavior is undefined.