2012-09-09 42 views
10

是否可以在C++中序列化和反序列化std::function,函数对象或闭包?怎么样? C++ 11是否有助于此?是否有任何库支持可用于此类任务(例如,在Boost中)?序列化函数对象

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


编辑:

为了澄清,其是要移动的功能应该是纯和自由侧效果的。所以我没有安全或状态不匹配问题。

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

+2

忘记它。查找“远程过程调用”的概念,以及它的流行实现。 –

+0

不,不,不。任何这样的对象,当你剥离漂亮的类型安全包装时,都是指向某些机器代码的指针。您既不能发送机器代码也不能发送指向其他进程或其他机器的指针。 –

+0

@ kerrek-sb我不确定RPC是否适合我的目的,在这里我有很多小函数对象在发送端不断构造和解构。以某种方式传输逻辑本身会更好。 – shaniaki

回答

6

C++有没有内置用于序列化支持,并从未与发送从一个过程到另一代码的思想设想,以免一台机器到另一台。可能这样做的语言通常同时具有IR(与机器无关的代码的中间表示)和反射。

因此,您只需编写一个用于传输所需操作的协议,而DSL方法肯定可行......取决于您希望执行的各种任务以及对性能的需求。

另一种解决方案是使用现有语言。例如,Redis NoSQL数据库嵌入了一个LUA引擎,并且可以执行LUA脚本,您可以执行相同的操作并在网络上传输LUA脚本。

8

是的函数指针和闭包。不适用于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,您可以通过使用setarch $(uname -m) -LR your_program开始your_program来关闭Linux。

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

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函数后面的未命名类的引用。 (这是_Function_handlerfunctional。)std::function将函数指针指向此包装类的静态方法(_M_invoke),并将其存储并加上闭包值。

不幸的是,一切都埋在private成员中,并且不存储闭包值的大小。 (不需要,因为lambda函数知道它的大小。)

因此std::function不适合序列化,但作为蓝图很好。我遵循它的操作,简化了很多(我只想序列化lambda表达式,而不是其他无数可调用的东西),将关闭值的大小保存在size_t中,并添加了(反)序列化方法。有用!

+1

但是这将取决于架构。例如,这不会从x86到arm。 – portforwardpodcast

+0

@daniel你可以用'std :: function'来代表最后一位代码吗? – subzero

+0

我在工作中做过,因此我必须先要求提供版权发布。我会报告回来! –