2017-06-19 54 views
0

我有一個大的配置結構,它由子結構,int,char,long和字符串組成。子結構也是由相同的元素構建而成的。沒有「保存」方法序列化一個大結構

此配置結構需要序列化並在羣集上的節點之間發送。

我正在尋找一種序列化方式,而不需要在每個結構體中添加「保存」方法,如穀類和增強庫所需。代碼由少數程序員共享,結構非常大。恐怕有人會更新結構或其substructs的一個忘記更新「保存方法相應

想法?

**在CPP

+1

二進制表示是一個選項嗎? –

+0

恐怕有人會更新結構或其子結構之一,並忘記更新「保存方法相應 - 這是測試的目的。如果你的配置可以與==很好地比較,那麼你可以serialise,de -serialise,然後比較&斷言相同 – UKMonkey

+0

@StephanLechner二進制表示是一個選項,我不在乎它是如何序列化的 – Epic

回答

0

如果你可以確定集羣中的所有節點具有相同的體系結構並執行相同的編譯代碼,但實際上可以以二進制模式傳輸數據,即作爲對象的「原始內存轉儲」。由於不同的體系結構和/或不同的編譯器可能導致所使用的數據類型的不同大小以及不同的「填充」,因此需要相同的體系結構/相同的編譯代碼。然後,發送方和接收方使用的內存佈局可能會不同,導致數據混亂。

請注意,您的「結構」(或類)必須是POD類型,即沒有虛擬構造函數/析構函數,也沒有虛擬成員函數,您可以使用「內存轉儲」初始化它。

如果您知道這些限制,請參閱以下代碼,該代碼通過以二進制模式寫入和讀取文件來「模擬」傳輸。調整此代碼以使用您選擇的頻道實際傳輸代碼,例如插座。

希望它有幫助。

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; 
} 
+0

我的結構不是POD,因爲它具有字符串,但是在閱讀完它後,最好使它們成爲char []並按照你的建議進行操作。我應該爲其他人注意,如果他們使用cpp 14,他們可以使用boost hana來遍歷結構並輕鬆地序列化 – Epic

0

加速提供了一個非侵入性的方式來序列,see here下的「非侵入式版本」

+0

鑑於OP已經聲明他們意識到boost,我不認爲這個答案 – UKMonkey

+0

他的問題意味着他認爲他必須使用boost來將保存方法放入課程中,而非非侵入式版本的情況並非如此 – mattideluxe

+0

@mattideluxe問題並非天氣將保存在內部。問題是開發人員可能會意外忘記在兩個地方都輸入新的值 – Epic

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 
} 

附:確保對齊不會影響您的尺寸。


UPD。

此圖書館可能會幫助您在magic_get。 同樣這兩篇文章都非常有趣An Introduction to Reflection in C++Fun with Reflection in C++

UPD.2

你可能想看看protocol buffers或類似的庫。

+0

tnx,我會閱讀他們 – Epic

+0

我遇到了在你的鏈接增加hana。這似乎允許遍歷結構成員。我不能使用它,因爲它需要cpp 14,但它可能對某人有用 – Epic

0

恐怕有人會更新結構或其substructs的一個忘記更新「保存方法相應

怎麼樣把一個

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

(或同等學歷)這方式,如果有人在結構中添加一個新變量,並且不更新序列化方法的預期大小,您將得到編譯器錯誤。

相關問題