通过直接转换为char数组来序列化POD数据是否安全?

J. *_*rez 5 c++ serialization mpi

假设这T是一个不包含指针的POD类型,我想序列化T(除了一些其他数据).我创建了以下函数来执行此操作:

template<class T> void serialize(const T& source, char*& dest)
{
  *(T*)dest = source;
  dest += sizeof(T);
}
template<class T> void deserialize(T& dest, char*& source)
{
  dest = *(T*)source;
  source += sizeof(T);
}
Run Code Online (Sandbox Code Playgroud)

这会导致任何问题,还是有任何编译器无法解决问题?换句话说,代码是:

template<class T> bool check_sanity(const T& obj)
{
  std::unique_ptr<char[]> buffer { new int[sizeof(T)] };
  serialize(obj, buffer);
  T new_obj;
  deserialize(new_obj, buffer); 
  return new_obj == obj;
}
Run Code Online (Sandbox Code Playgroud)

曾经回归虚假?(假设T是POD,没有人重载==运算符).

我正在编写这些序列化方法以与MPI一起使用,它们将在程序开始时用于分发簿记所需的一些数据,因此相同的程序将始终对数据进行序列化和反序列化.

Mik*_*sev 3

我看到了几个问题。一个较小的:

*(T*)dest = source;
Run Code Online (Sandbox Code Playgroud)

IIRC,这是 UB,因为违反了别名规则(char *可以为任何其他指针别名,但这意味着您可以通过指针访问某个对象char *,但反之则不然,如您的示例所示)。

换句话说,代码会: ... 会返回 false 吗?

可能不是,但您提到序列化不仅仅是单个对象。

所以,主要问题是对齐

std::unique_ptr<char[]> buffer { new char[sizeof(int) + 1] };
char x = 0;
int y = 0;
serialize(x, buffer);
serialize(y, buffer); // may crash or write into wrong location
Run Code Online (Sandbox Code Playgroud)

故障线路相同​​(但deserialize也受到影响):

*(T*)dest = source; // source is int, dest is not aligned
Run Code Online (Sandbox Code Playgroud)

编译器将假设 dest 已正确对齐,并使用 CPU 指令进行对齐存储(在 ARM 架构上,这将导致真正的问题)。

解决方案是使用 memcpy 代替:

memcpy(dest, &source, sizeof(T));
Run Code Online (Sandbox Code Playgroud)

无需担心性能。现代编译器能够很好地优化已知大小的对象的 memcpy。