我有一个旨在存储用户定义数据(即来自插件)的结构。它有一个具有给定最大大小的char[]
来存储该数据。
struct A
{
// other members omitted
// data meant to be type punned, only contains PODs
char data[256];
};
然后有一个示例用户结构,它具有静态函数以从A
投射自己。
struct B
{
int i;
double d;
static B& FromA_ref(A& a)
{
// static_assert that sizeof(B) < sizeof(A::data)
return * reinterpret_cast<B*>(a.data);
}
};
我使用g++ -O3 -std=c++0x -Wall -o test test.cpp
(GCC 4.6.1)编译。
这会触发dereferencing type-punned pointer will break strict-aliasing rules
警告。我认为这样就行了,因为我使用char[]
作为存储,我认为它将遵循与char*
相同的规则。我觉得很奇怪,事实并非如此。不是吗?好吧,......我现在无法改变它,所以让我们继续前进。
现在让我们考虑以下方法:
struct B
{
....
static B* FromA_ptr(A& a)
{
// static_assert that sizeof(B) < sizeof(A::data)
return reinterpret_cast<B*>(a.data);
}
}
由于我在这里没有取消引用任何内容,GCC不会输出任何警告。当我稍后使用指针B
时,它也不会。
A a;
auto b = B::FromA_ptr(a);
b->i = 2; // no warnings.
但这样做是否安全?我觉得我一直在解决问题而不是解决问题。对我来说->
仍然以某种方式取消引用该变量。
或者,有没有更好的方法来实现这种效果? I.E.从另一个结构中的存储中获取一个可修改的引用(或指针)? (由于定义A
时存储的类型集不可知,因此联合将无法工作,而某些类型可能通过插件添加,memcpy
会强制我来回复制数据似乎是迄今为止唯一安全的方式)
答案 0 :(得分:4)
答案是否定的,不安全(见SO question)
GCC将假设指针不能别名。例如,如果您通过一个进行分配然后从另一个进行读取,GCC可以作为优化对读取和写入进行重新排序 - 我已经在生产代码中看到了这种情况,调试起来并不愉快。
所使用的类型的属性(( may_alias ))可能是最接近禁用特定代码段假设的。