У меня есть структура, которая предназначена для хранения пользовательских данных (т. Е. Из плагина). У него есть такой 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.
Но безопасно ли это делать? Мне кажется, что я решил проблему, а не решил ее. Для меня ->
все еще как-то разыменовывает переменную.
В качестве альтернативы, есть ли лучший способ добиться эффекта? И.Е. получить модифицируемую ссылку (или указатель), приведенную из хранилища внутри другой структуры? (Объединение не будет работать, так как набор сохраненных типов неизвестен, когда определено A
, а некоторые могут быть добавлены через плагины, memcpy
заставит меня копировать данные туда и обратно, хотя это, кажется, пока единственный безопасный путь)