Я ничто не нашел непосредственно связанным в поиске, поэтому простите, если это - дубликат.
То, что я надеюсь делать, сериализируют данные через сетевое соединение. Мой подход должен преобразовать все, что я должен передать a std::vector< uint8_t >
и на получении сторона распаковывают данные в соответствующие переменные. Мой подход похож на это:
template
inline void pack (std::vector< uint8_t >& dst, T& data) {
uint8_t * src = static_cast < uint8_t* >(static_cast < void * >(&data));
dst.insert (dst.end (), src, src + sizeof (T));
}
template
inline void unpack (vector & src, int index, T& data) {
copy (&src[index], &src[index + sizeof (T)], &data);
}
Как который я использую
vector< uint8_t > buffer;
uint32_t foo = 103, bar = 443;
pack (buff, foo);
pack (buff, bar);
// And on the receive side
uint32_t a = 0, b = 0;
size_t offset = 0;
unpack (buffer, offset, a);
offset += sizeof (a);
unpack (buffer, offset, b);
Мое беспокойство
uint8_t * src = static_cast < uint8_t* >(static_cast < void * >(&data));
строка (который я понимаю, чтобы сделать то же как reinterpret_cast
). Существует ли лучший способ выполнить это без двойного броска?
Мой наивный подход должен был просто использовать static_cast< uint8_t* >(&data)
который отказавший. Мне сказали в прошлом это reinterpret_cast
плохо. Таким образом, я хотел бы избежать его (или конструкция, которую я в настоящее время имею), если это возможно.
Конечно, всегда существует uint8_t * src = (uint8_t *)(&data)
.
Предложения?
Мое предложение - игнорировать всех людей, которые говорят вам, что reinterpret_cast
- это плохо. Они говорят вам, что это плохо, потому что обычно это не очень хорошая практика - брать карту памяти одного типа и притворяться, что это другой тип. Но в данном случае это именно то, что вы хотите сделать, поскольку вся ваша цель - передать карту памяти в виде серии байтов.
Это гораздо лучше, чем использовать double-static_cast
, поскольку он полностью детализирует тот факт, что вы берете один тип и намеренно притворяетесь, что это что-то другое. Именно для такой ситуации и предназначен reinterpret_cast
, и уклонение от его использования с помощью промежуточного указателя void - это просто затемнение смысла без какой-либо пользы.
Также, я уверен, что вы знаете об этом, но следите за указателями в T.
Вы можете избавиться от одного приведения, используя тот факт, что любой указатель может быть неявно приведен к void *
. Кроме того, вы можете добавить несколько const
:
//Beware, brain-compiled code ahead!
template <typename T>
inline void encode (std::vector< uint8_t >& dst, const T& data)
{
const void* pdata = &data;
uint8_t* src = static_cast<uint8_t*>(pdata);
dst.insert(dst.end(), src, src + sizeof(T));
}
Возможно, вы захотите добавить проверку во время компиляции для T
, являющегося POD, без структуры ,
] и без указателя.
Однако интерпретация памяти некоторых объектов на байтовом уровне никогда не будет спасительной, точка. Если вам нужно это сделать, сделайте это в красивой обертке (как вы это сделали) и преодолейте это. Когда вы переносите на другую платформу / компилятор, обратите внимание на эти вещи.
Здесь вы не выполняете никакого фактического кодирования , вы просто копируете необработанное представление данных из памяти в байтовый массив, а затем отправляете его по сеть. Это не сработает. Вот краткий пример того, почему:
struct A {
int a;
};
struct B {
A* p_a;
}
Что происходит, когда вы используете свой метод для отправки B
по сети? Получатель получает p_a
, адрес некоторого объекта A
на вашем компьютере, но этого объекта нет на его машине. И даже если вы отправите им объект A
, он не будет по тому же адресу. Это не сработает, если вы просто отправите необработанную структуру B
. И это даже без учета более тонких проблем, таких как порядок байтов и представление с плавающей запятой, которые могут повлиять на передачу таких простых типов, как int
и double
.
То, что вы делаете прямо сейчас, принципиально ничем не отличается от простого преобразования в uint8_t *
в том, будет ли это работать или нет (это не сработает, за исключением самых тривиальных случаев ).
Что вам нужно сделать, так это разработать метод сериализации . Сериализация означает любой способ решения такого рода проблем: как передать объекты в памяти в сеть в такой форме, чтобы их можно было осмысленно реконструировать на другой стороне. Это непростая задача, но проблема известная и неоднократно решаемая. Вот хорошая отправная точка для чтения: http://www.parashift.com/c++-faq-lite/serialization.html