безопасно ли передавать std :: variant по сети, кросс-платформенный

std :: option - это замена union.

Но объединение может безопасно проходить по сети и получать на другой платформе (другом компиляторе или арке). Может ли std :: option это сделать?

Например, у меня есть две машины A и B. A - это windows, MSVC 19.4. B - это Linux, gcc (или другие компиляторы, например MSVC 17). Компилирую код под A (или B):

std::variant<int, double> v = 1; // holds int.
f.write(&v, sizeof(v));

Может ли B прочитать правильное значение, используя следующий код из того же файла?

std::variant<int, double> v;
f.read(&v, sizeof(v));

Если std :: variant не может безопасно пройти по сети. Есть ли какая-нибудь библиотека? boost :: option? или, может быть, создать настраиваемую реализацию, которая действует как std :: variant?


person 欢乐的Xiaox    schedule 24.02.2020    source источник
comment
Вы не должны даже передавать int по сети таким образом, не говоря уже о std::variant. Используйте библиотеку сериализации или сериализуйте ее самостоятельно.   -  person bolov    schedule 24.02.2020
comment
На самом деле внутри него скрывается хороший вопрос: является ли вариант, содержащий только POD, самим POD. Перечитывая (кратко) определение варианта, в нем ничего не говорится по этому поводу, поэтому я скажу, что он не уточняется.   -  person Sam Varshavchik    schedule 24.02.2020
comment
@SamVarshavchik По крайней мере, в C ++ 20 это так, не знаю, считается ли это отчетом о дефектах C ++ 17. Измените результаты с p0602r4.   -  person walnut    schedule 24.02.2020
comment
@OP: ваш код тоже не компилируется, если f - стандартный поток. Вам нужно явно указать reinterpret_cast на char*, чтобы выполнить эту компиляцию.   -  person walnut    schedule 24.02.2020


Ответы (1)


В общем, ни объединение, ни вариант, ни многие другие типы в C ++ не могут быть выгружены из памяти в файл и затем безопасно прочитаны.

При передаче данных между несколькими платформами (имеется в виду оборудование) многие вещи могут сделать передачу небезопасной:

  • Endianness (большинство современных машин, таких как x86, имеют прямой порядок байтов)
  • Размер (тип int, о котором вы говорите, например, может составлять 4 байта на одной платформе, 8 на другой.)
  • Сколько бит имеет байт (CHAR_BIT, обычно 8, если это применимо только к нескольким загадочным платформам)
  • Используемая реализация с плавающей запятой. (IEEE-754 сегодня используется большинством оборудования, но стандарт C ++ этого не требует )

По этой причине единственным безопасным способом передачи данных между платформами является использование стандартизированного промежуточного формата данных, который обычно называется сериализацией. В этом вам могут помочь многие библиотеки. Некоторые из них

Если вопрос больше касается структуры памяти std::variant, то же самое касается std::variant, как и любого другого std контейнера: структура памяти определяется реализацией. (Под реализацией здесь подразумевается используемая реализация стандартной библиотеки). Например, некоторая стандартная библиотека выполняет небольшую оптимизацию строки в std::string, которая может содержать небольшие строки (скажем, менее 32 символов) без выделения кучи. Некоторые этого не делают. Таким образом, у вас очень большая разница в расположении памяти для одного и того же типа.

Таким образом, либо вы гарантируете, что и отправитель, и получатель имеют одинаковую аппаратную и стандартную реализацию библиотеки, либо вы используете библиотеку сериализации, чтобы гарантировать получение тех же данных, что и отправленные вами.

person Jan15    schedule 24.02.2020