Неправильно ли сериализовывать объекты структуры с помощью memcpy?Сериализация структур C-стиля (с использованием C++)
В одном из моих проектов я выполняю следующее: я memcpy объект struct, base64 закодировал его и запишу в файл. При анализе данных я делаю обратный. Кажется, что он работает нормально, но в некоторых ситуациях (например, при использовании WINDOWPLACEMENT
для HWND проигрывателя Windows Media) получается, что декодированные данные не соответствуют sizeof(WINDOWPLACEMENT)
.
Вот некоторые фрагменты кода:
// Using WINDOWPLACEMENT from Windows API headers:
typedef struct tagWINDOWPLACEMENT {
UINT length;
UINT flags;
UINT showCmd;
POINT ptMinPosition;
POINT ptMaxPosition;
RECT rcNormalPosition;
#ifdef _MAC
RECT rcDevice;
#endif
} WINDOWPLACEMENT;
static std::string EncodeWindowPlacement(const WINDOWPLACEMENT & inWindowPlacement)
{
std::stringstream ss;
{
Poco::Base64Encoder encoder(ss); // From the Poco C++ libraries
const char * offset = reinterpret_cast<const char*>(&inWindowPlacement);
std::vector<char> buffer(offset, offset + sizeof(inWindowPlacement));
for (size_t idx = 0; idx != buffer.size(); ++idx)
{
encoder << buffer[idx];
}
encoder.close();
}
return ss.str();
}
static WINDOWPLACEMENT DecodeWindowPlacement(const std::string & inEncoded)
{
std::string decodedString;
{
std::istringstream istr(inEncoded);
Poco::Base64Decoder decoder(istr); // From the Poco C++ libraries
decoder >> decodedString;
assert(decoder.eof());
if (decoder.fail())
{
throw std::runtime_error("Failed to parse Window placement data from the configuration file.");
}
}
if (decodedString.size() != sizeof(WINDOWPLACEMENT))
{
// !! Occurs frequently !!
throw std::runtime_error("Errors occured during parsing of the Window placement.");
}
WINDOWPLACEMENT windowPlacement;
memcpy(&windowPlacement, &decodedString[0], decodedString.size());
return windowPlacement;
}
Я знаю, что копирование классов в C++ с использованием тетсра может вызвать проблемы, потому что копию конструкторы не выполняется должным образом. Я не уверен, что это относится и к структурам C-стиля. Или сериализуется сбрасывание памяти просто не сделано?
Обновление: Ошибка в Base64Encoder/Decoder Poco не является невозможной, но маловероятной. Его тестовые примеры выглядят довольно тщательно: Base64Test.cpp.
memcpy не более или менее вероятно вызывает проблемы с классами, чем с structs. За исключением случаев, когда вы принимаете во внимание тот факт, что большинство людей используют структуры как типы POD и классы для более сложных типов. structs в C++ также используют конструкторы копирования. И конструктор копии по умолчанию эквивалентен memcpy, по крайней мере для типов POD. –
Что касается точки Ганса, разумно сказать компилятору явную «пакетную» инструкцию в определении структуры и использовать поля фиксированного размера. Если вы не можете этого сделать, то другой вариант - поместить поле размера в качестве первого члена структуры. Поле размера может использоваться как версия, его можно сравнить при загрузке, а будущие версии могут корректировать вещи, если они не совпадают. –