reinterpret_cast 在指向模板聚合类型的指针上的安全性
Safety of reinterpret_cast on pointer to template aggregate type
我想知道我接下来对 reinterpret_cast
的使用是否是未定义的行为。
给定模板聚合,例如...
template<typename T>
struct Container
{
Container(T* p) : ptr(p) { }
...
T* ptr;
};
... 和类似 ...
的类型层次结构
struct A { };
struct B : A { };
以下转换是否安全,因为 B
是 A
的动态类型 ...
Container<B>* b = new Container<B>( new B() );
Container<A>* a = reinterpret_cast<Container<A>*>(b);
...至于我现在可以安全地使用 a->ptr
及其(可能是虚拟的)成员吗?
我使用它的代码可以很好地编译和执行(Clang,OS X),但我担心我已经放置了一颗定时炸弹。我想 Container<T>
的每个实例都共享相同的布局和大小,所以这应该不是问题,对吧?
看看 cppreference.com 关于 reinterpret_cast
的说法,似乎有一个合法使用的声明涵盖了我正在尝试做的事情...
Type aliasing
When a pointer or reference to object of type T1 is reinterpret_cast (or C-style cast) to a pointer or reference to object of a different type T2, the cast always succeeds, but the resulting pointer or reference may only be accessed if both T1 and T2 are standard-layout types and one of the following is true:
...
T2 is an aggregate type or a union type which holds one of the aforementioned types as an element or non-static member (including, recursively, elements of subaggregates and non-static data members of the contained unions): this makes it safe to cast from the first member of a struct and from an element of a union to the struct/union that contains it.
我很感激我在这件事上似乎走错了路。那不是我关心的。我只想知道我所做的是否安全/合法。在此先感谢您的帮助。
无论类型别名是否符合标准,您可能还有其他问题。
I guess every instance of Container<T>
shares the same layout and
size so it shouldn't be a problem, right?
实际上,并非 Container<T>
的每个实例都共享相同的布局!如 this question 中所述,模板成员仅在使用时创建,因此如果每种类型使用不同的成员,您的 Container<A>
和 Container<B>
可能具有不同的内存布局。
there seems to be a statement for legal use that covers what I'm trying to do ...
那不是那个例外的意思。该异常表示 given
struct S { int i; } s;
您可以使用 *reinterpret_cast<int *>(&s)
访问 s.i
。
您尝试执行的操作没有类似的例外情况。你试图做的事情在 C++ 中根本无效。即使是下面的也是无效的:
struct S { int i; };
struct T { int i; };
int f(S s) { return ((T &) s).i; }
并且编译器会基于您不会编写那样的代码的假设进行优化。
对于当前编译器在 运行 时失败的实际示例:
#include <cstdlib>
struct S { int i; };
struct T { int i; };
void f(S *s, T *t) { int i = s->i; t->i++; if (s->i == i) std::abort(); }
这里,GCC优化掉了检查s->i == i
(GCC 4.9.2,命令行选项中有-O2
),无条件调用std::abort()
,因为编译器知道s
和 t
不可能指向相同的内存区域。即使您可能会尝试将其称为
int main() { S s = { 0 }; f(&s, reinterpret_cast<T *>(&s)); }
我想知道我接下来对 reinterpret_cast
的使用是否是未定义的行为。
给定模板聚合,例如...
template<typename T>
struct Container
{
Container(T* p) : ptr(p) { }
...
T* ptr;
};
... 和类似 ...
的类型层次结构struct A { };
struct B : A { };
以下转换是否安全,因为 B
是 A
的动态类型 ...
Container<B>* b = new Container<B>( new B() );
Container<A>* a = reinterpret_cast<Container<A>*>(b);
...至于我现在可以安全地使用 a->ptr
及其(可能是虚拟的)成员吗?
我使用它的代码可以很好地编译和执行(Clang,OS X),但我担心我已经放置了一颗定时炸弹。我想 Container<T>
的每个实例都共享相同的布局和大小,所以这应该不是问题,对吧?
看看 cppreference.com 关于 reinterpret_cast
的说法,似乎有一个合法使用的声明涵盖了我正在尝试做的事情...
Type aliasing When a pointer or reference to object of type T1 is reinterpret_cast (or C-style cast) to a pointer or reference to object of a different type T2, the cast always succeeds, but the resulting pointer or reference may only be accessed if both T1 and T2 are standard-layout types and one of the following is true:
...
T2 is an aggregate type or a union type which holds one of the aforementioned types as an element or non-static member (including, recursively, elements of subaggregates and non-static data members of the contained unions): this makes it safe to cast from the first member of a struct and from an element of a union to the struct/union that contains it.
我很感激我在这件事上似乎走错了路。那不是我关心的。我只想知道我所做的是否安全/合法。在此先感谢您的帮助。
无论类型别名是否符合标准,您可能还有其他问题。
I guess every instance of
Container<T>
shares the same layout and size so it shouldn't be a problem, right?
实际上,并非 Container<T>
的每个实例都共享相同的布局!如 this question 中所述,模板成员仅在使用时创建,因此如果每种类型使用不同的成员,您的 Container<A>
和 Container<B>
可能具有不同的内存布局。
there seems to be a statement for legal use that covers what I'm trying to do ...
那不是那个例外的意思。该异常表示 given
struct S { int i; } s;
您可以使用 *reinterpret_cast<int *>(&s)
访问 s.i
。
您尝试执行的操作没有类似的例外情况。你试图做的事情在 C++ 中根本无效。即使是下面的也是无效的:
struct S { int i; };
struct T { int i; };
int f(S s) { return ((T &) s).i; }
并且编译器会基于您不会编写那样的代码的假设进行优化。
对于当前编译器在 运行 时失败的实际示例:
#include <cstdlib>
struct S { int i; };
struct T { int i; };
void f(S *s, T *t) { int i = s->i; t->i++; if (s->i == i) std::abort(); }
这里,GCC优化掉了检查s->i == i
(GCC 4.9.2,命令行选项中有-O2
),无条件调用std::abort()
,因为编译器知道s
和 t
不可能指向相同的内存区域。即使您可能会尝试将其称为
int main() { S s = { 0 }; f(&s, reinterpret_cast<T *>(&s)); }