c++ - 序列化函数对象

标签 c++ serialization c++11 closures function-object

是否可以在 C++ 中对 std::function、函数对象或闭包进行序列化和反序列化?如何? C++11 是否促进了这一点?是否有任何库支持可用于此类任务(例如,在 Boost 中)?

例如,假设一个 C++ 程序有一个 std::function 需要与驻留在另一台机器上的另一个 C++ 程序进行通信(例如通过 TCP/IP 套接字)。在这种情况下你有什么建议?


编辑:

为了澄清,要移动的函数应该是纯的且无副作用的。所以我没有安全或状态不匹配的问题。

该问题的解决方案是构建一个小型嵌入式领域特定语言并将其抽象语法树序列化。 我希望我能找到一些语言/库支持来移动独立于机器的函数表示。

最佳答案

对于函数指针和闭包是。不适用于 std::function

函数指针是最简单的——它只是一个和其他指针一样的指针,因此您可以将其读取为字节:

template <typename _Res, typename... _Args>
std::string serialize(_Res (*fn_ptr)(_Args...)) {
  return std::string(reinterpret_cast<const char*>(&fn_ptr), sizeof(fn_ptr));
}

template <typename _Res, typename... _Args>
_Res (*deserialize(std::string str))(_Args...) {
  return *reinterpret_cast<_Res (**)(_Args...)>(const_cast<char*>(str.c_str()));
}                   

但我惊讶地发现,即使没有重新编译,函数的地址也会在每次调用程序时发生变化。如果您想传输地址,则不是很有用。这是由于 ASLR ,您可以在 Linux 上通过使用 setarch $(uname -m) -LR your_program 启动 your_program 来关闭它。

现在您可以将函数指针发送到运行相同程序的不同机器,然后调用它! (这不涉及传输可执行代码。但除非您在运行时生成可执行代码,否则我认为您不会在寻找那个。)

lambda 函数完全不同。

std::function<int(int)> addN(int N) {
  auto f = [=](int x){ return x + N; };
  return f;
}

f 的值将是捕获的int N。它在内存中的表示与 int 相同!编译器为 lambda 生成一个未命名的类,其中 f 是一个实例。这个类的 operator() 重载了我们的代码。

未命名的类存在序列化问题。它还提出了从函数返回 lambda 函数的问题。后一个问题由 std::function 解决。

std::function 据我了解是通过创建一个模板化的包装类来实现的,该类通过模板类型参数有效地保存对 lambda 函数背后的未命名类的引用。 (这是 functional 中的 _Function_handler。) std::function 采用指向此包装类的静态方法 (_M_invoke) 的函数指针并存储它加上闭包值。

不幸的是,所有内容都隐藏在 private 成员中,并且没有存储闭包值的大小。 (它不需要,因为 lambda 函数知道它的大小。)

所以 std::function 不适合序列化,但可以很好地作为蓝图。我遵循它所做的,简化了很多(我只想序列化 lambda,而不是无数其他可调用的东西),将闭包值的大小保存在 size_t 中,并为 (de ) 序列化。有效!

关于c++ - 序列化函数对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12338265/

相关文章:

c++ - std::ref 和 swap 函数似乎不能很好地协同工作

C++ 将 bool 转换为 int - 标准

c++ - 无法在C++中打开头文件

PHP 5 - 序列化对象并存储它们的关系

c++ - ICU 与 C++ 中的 Boost 语言环境

c++ - 模板转换运算符,需要 'const' 关键字

c# - XML 序列化 - 大数据(20GB),OutOfMemoryException

python - Django - 如何序列化继承

c++ - 使用 Lambda 和递归函数调用了解 QTimer

c++ - 指定默认模板