reinterpret_cast 会导致未定义的行为吗?
Does reinterpret_cast lead to undefined behavior?
我有一个 class 模板 A
,其中包含一个指针容器 (T*
):
template <typename T>
class A {
public:
// ...
private:
std::vector<T*> data;
};
和一堆功能,例如:
void f(const A<const T>&);
void g(const A<const T>&);
可以通过从 A<const T>
到 A<T>
的强制转换来调用这些函数吗?
A<double> a;
...
auto& ac = reinterpret_cast<const A<const double>&>(a);
f(ac);
我很确定这段代码有未定义的行为。
在现实生活中使用这种转换是否危险?
由于 A<double>
和 A<const double>
是不相关的类型,它实际上是未指定的(最初我认为未定义的)行为,相应地是的,在现实生活中使用它是一个坏主意:你永远不知道什么系统( s) 或编译器,你可以移植到那个改变行为的奇怪方式。
参考:
5.2.10/11:
An lvalue expression of type T1 can be cast to the type “reference to
T2” if an expression of type “pointer to T1” can be explicitly
converted to the type “pointer to T2” using a reinterpret_cast. That
is, a reference cast reinterpret_cast(x) has the same effect as
the conversion *reinterpret_cast(&x) with the built-in & and *
operators (and similarly for reinterpret_cast(x)).
所以他们将我们重定向到更早的部分 5.2.10/7:
An object pointer can be explicitly converted to an object pointer of
a different type. ... ... Converting a prvalue of type
“pointer to T1” to the type “pointer to T2” (where T1 and T2 are
object types and where the alignment requirements of T2 are no
stricter than those of T1) and back to its original type yields the
original pointer value. The result of any other such pointer
conversion is unspecified.
如果 f
和 g
是适用于容器的算法,简单的解决方案是将它们更改为适用于范围(迭代器对)的模板算法。
虽然 reinterpret_cast
本身可能是未指定的行为,但在完成转换后尝试访问参数是未定义的行为。
N3337 [basic.lval]/10:
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.
你的例子就是上面的none。
我有一个 class 模板 A
,其中包含一个指针容器 (T*
):
template <typename T>
class A {
public:
// ...
private:
std::vector<T*> data;
};
和一堆功能,例如:
void f(const A<const T>&);
void g(const A<const T>&);
可以通过从 A<const T>
到 A<T>
的强制转换来调用这些函数吗?
A<double> a;
...
auto& ac = reinterpret_cast<const A<const double>&>(a);
f(ac);
我很确定这段代码有未定义的行为。
在现实生活中使用这种转换是否危险?
由于 A<double>
和 A<const double>
是不相关的类型,它实际上是未指定的(最初我认为未定义的)行为,相应地是的,在现实生活中使用它是一个坏主意:你永远不知道什么系统( s) 或编译器,你可以移植到那个改变行为的奇怪方式。
参考:
5.2.10/11:
An lvalue expression of type T1 can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_cast. That is, a reference cast reinterpret_cast(x) has the same effect as the conversion *reinterpret_cast(&x) with the built-in & and * operators (and similarly for reinterpret_cast(x)).
所以他们将我们重定向到更早的部分 5.2.10/7:
An object pointer can be explicitly converted to an object pointer of a different type. ... ... Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.
如果 f
和 g
是适用于容器的算法,简单的解决方案是将它们更改为适用于范围(迭代器对)的模板算法。
虽然 reinterpret_cast
本身可能是未指定的行为,但在完成转换后尝试访问参数是未定义的行为。
N3337 [basic.lval]/10:
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.
你的例子就是上面的none。