сериализируйте какой-либо тип данных, поскольку вектор <uint8_t> - использует reinterpret_cast?

Я ничто не нашел непосредственно связанным в поиске, поэтому простите, если это - дубликат.

То, что я надеюсь делать, сериализируют данные через сетевое соединение. Мой подход должен преобразовать все, что я должен передать 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).

Предложения?

7
задан Community 23 May 2017 в 12:34
поделиться

3 ответа

Мое предложение - игнорировать всех людей, которые говорят вам, что reinterpret_cast - это плохо. Они говорят вам, что это плохо, потому что обычно это не очень хорошая практика - брать карту памяти одного типа и притворяться, что это другой тип. Но в данном случае это именно то, что вы хотите сделать, поскольку вся ваша цель - передать карту памяти в виде серии байтов.

Это гораздо лучше, чем использовать double-static_cast, поскольку он полностью детализирует тот факт, что вы берете один тип и намеренно притворяетесь, что это что-то другое. Именно для такой ситуации и предназначен reinterpret_cast, и уклонение от его использования с помощью промежуточного указателя void - это просто затемнение смысла без какой-либо пользы.

Также, я уверен, что вы знаете об этом, но следите за указателями в T.

17
ответ дан 6 December 2019 в 06:23
поделиться

Вы можете избавиться от одного приведения, используя тот факт, что любой указатель может быть неявно приведен к 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, без структуры , ] и без указателя.

Однако интерпретация памяти некоторых объектов на байтовом уровне никогда не будет спасительной, точка. Если вам нужно это сделать, сделайте это в красивой обертке (как вы это сделали) и преодолейте это. Когда вы переносите на другую платформу / компилятор, обратите внимание на эти вещи.

2
ответ дан 6 December 2019 в 06:23
поделиться

Здесь вы не выполняете никакого фактического кодирования , вы просто копируете необработанное представление данных из памяти в байтовый массив, а затем отправляете его по сеть. Это не сработает. Вот краткий пример того, почему:

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

1
ответ дан 6 December 2019 в 06:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: