序列化一个没有“保存”方法的大型结构

时间:2017-06-19 09:45:04

标签: c++ serialization

我有一个大型配置结构,它包含子结构,int,char,long和字符串。子结构也是用相同的元素构建的。

此配置结构需要序列化并在群集上的节点之间发送。

我一直在寻找一种序列化方法,而不是像谷物和boost库那样在每个结构中制作“保存”方法。代码在少数程序员之间共享,结构非常大。我担心有人会更新结构或其中一个子结构而忘记更新“相应的保存方法”

想法?

** in cpp

4 个答案:

答案 0 :(得分:1)

如果可以确定集群中的所有节点具有相同的体系结构并执行相同的编译代码,则实际上可以以二进制模式传输数据,即作为对象的“原始内存转储”。需要相同的体系结构/相同的编译代码,因为不同的体系结构和/或不同的编译器可能导致所使用的数据类型的不同大小以及不同的“填充”。然后,发送方和接收方使用的内存布局可能不同,导致数据混乱。

请进一步注意,您的“struct”(或类)必须是POD类型,即没有虚拟构造函数/析构函数,没有虚拟成员函数,以便您可以使用“内存转储”对其进行初始化。

如果您了解这些限制,请参阅以下代码,该代码通过以二进制模式写入和读取文件来“模拟”传输。调整此代码以使用您选择的频道实际传输代码,例如套接字。

希望它有所帮助。

#include <fstream>
#include <iostream>

using namespace std;

struct myStruct {
    int x;
    int y;
    char name[10];
    double z;

    void printOnConsole() {
        cout << "x:" << x << ";y:" << y << ";name:"<< name << ";z:" << z << endl;
    }
    void writeBinary(ofstream &out) {
        out.write((char*)this, sizeof(*this));
    }
    bool readBinary(ifstream &in) {
        in.read((char*)this, sizeof(*this));
        return in.gcount() == sizeof(*this);
    }
};


int main()
{
    myStruct myStructObjs[] = {
        { 10, 20, "Herbert", 3.5 },
        { 30, 40, "Anton", 4.6 }
    };
    cout << "Objects to be transferred:" << endl;
    myStructObjs[0].printOnConsole();
    myStructObjs[1].printOnConsole();

    cout << "Simulating transfer:" << endl;
    ofstream send("data.bin", ios_base::binary | ios_base::out);
    if (send) {
        myStructObjs[0].writeBinary(send);
        myStructObjs[1].writeBinary(send);
        send.close();
        cout << "Two objects transferred." << endl;
    }
    else {
        cout << "Error 'sending' data." << endl;
        return 1;
    }


    cout << "Simulating receive:" << endl;
    ifstream receive("data.bin", ios_base::binary);
    if (receive) {
        myStruct receivedObj;
        int n = 0;
        while (receivedObj.readBinary(receive)) {
            receivedObj.printOnConsole();
            n++;
        }
        cout << n << " objects received." << endl;
    }
    else {
        cout << "Error 'receiving' data." << endl;
        return 1;
    }

    return 0;
}

答案 1 :(得分:0)

Boost提供了一种非侵入性的序列化方式,{&3;}非侵入式版本&#34;

答案 2 :(得分:0)

C ++中没有任何反映。 QT和虚幻引擎正在使用自己的编译步骤来为此目的创建代码反射。您也可以查看cpp3k这是一个铿锵声。

我可以建议你一种方法来确保在保存函数中没有正确更新的情况下修改结构会很明显:​​

struct myData {
int32_t a;
uint8_t b;
};

void save(const myData& data) {
    save(data.a);
    save(data.b);
    assert(sizeof(myData) == 5); // When adding new elements to myData make sure to update this function
}

P.S。确保对齐不会弄乱你的尺寸。

UPD。

此库可能会帮助您magic_get。 这两篇文章也非常有趣An Introduction to Reflection in C++Fun with Reflection in C++

UPD.2

您可能需要查看protocol buffers或类似的库。

答案 3 :(得分:0)

  

我担心有人会更新结构或其中一个子结构而忘记更新“相应的保存方法”

怎么样放

McCfgStruct::serialize(...) {
  std::static_assert(sizeof(MyCfgStruct) == 32);
}

(或等效)这样,如果有人在结构中添加了一个新变量,并且没有更新serialize方法的预期大小,则会出现编译错误。