2017-05-25 29 views
1

我有一個數據模型,它有很多成員,它們中的很多都是自己的大數據模型,並且這樣的嵌套深度不同。頂級類別代表序列化併發送到服務器進行備份的整體模型。作爲調試步驟,我們想要反序列化最近的備份,並將其與備份時的內存數據模型進行比較,這應該是相同的。最明顯的方法是在當前模型及其序列化和後來反序列化的版本上應用operator==不帶操作符的類平等檢查==

問題是,自定義數據結構的嵌套和數量的程度將需要大量的代碼來編寫所有這些operator==實現。更不用說那些單獨的實現中的許多將單獨用很多線來比較每個成員的平等。我們很容易就會在operator==上花費1k行代碼。即使我們這麼做,程序員在這樣的事情上仍然有很大的空間。

對於快速和骯髒(雖然可靠)的等同性檢查,也許使用更低層次的技術,或任何不需要幾天除了編寫operator==函數之外什麼都不做的任何替代方法嗎?

+0

如果你正在考慮'memcmp()',我不會推薦'memcmp()'。 –

+0

難道你不能將內存中的數據轉儲到文件中,然後做一個'diff'嗎? – Rakete1111

+0

@ Rakete1111也許我可以,如果我知道如何。這就是爲什麼我問這個問題。 – johnbakers

回答

2

tie解決方案將是你最好的選擇。

struct equal_by_tie { 
    template<class T> 
    using enable = std::enable_if_t<std::is_base_of<equal_by_tie, T>,bool>; 
    template<class T> 
    friend enable<T> 
    operator==(T const& lhs, T const& rhs) { 
    return mytie(lhs) == mytie(rhs); 
    } 
    template<class T> 
    friend enable<T> 
    operator!=(T const& lhs, T const& rhs) { 
    return mytie(lhs) != mytie(rhs); 
    } 
}; 

現在你必須寫

struct some_thing : equal_by_tie { 
public: 
    friend auto mytie(some_thing const& self) { 
    return std::tie(self.x, self.y, self.mem3); 
    } 
}; 

==!=是爲你寫的。

目前沒有辦法審覈mytie是否正確寫入,除非在C++ 17中有一些誠實不值得考慮的黑客行爲(結構化綁定,它是一個可怕的黑客,不要問)。

一種方法可以減少mytie錯誤的機會是使用它更多

以它的方式實現swap(也許使用與上面的operator==相同的父類欺騙)。根據swapmytie執行operator=。對friend std::size_t hash(Foo const&)執行相同的操作,並將其掛接到標準篩選器中。

堅持要求mytie與您的數據聲明的順序相同,並使其與父實例綁定爲子綁定。編寫一個函數,將您的系統結構/類對齊考慮在內,並計算的結構constexpr中的大小。靜態聲明Foocalc_struct_size(tag<decltype(mytie(std::declval<Foo&>()))>)的大小匹配。 (根據需要添加vtables或類似的軟件因素)。現在改變結構的佈局而不觸及mytie會導致不好的事情發生。

比較mytie中每對字段的指針不等,以確保不重複同一個字段兩次;嘗試確保在運行時優化到true(棘手,因爲您需要在調試中執行此操作,並且調試通常關閉了優化;也許這是您希望僅在發佈時執行的斷言的唯一情況建立!)。

你也想做一些理智的檢查。如果您的mytie包含原始指針==是錯誤的,並且對於智能指針是相同的;你想要你的==是一個深刻的平等。

爲此,也許==錯誤的東西

struct deep_equal_by_tie { 
    template<class T> 
    using enable = std::enable_if_t<std::is_base_of<equal_by_tie, T>,bool>; 
    template<class T> 
    friend enable<T> 
    deep_equal(T const& lhs, T const& rhs) { 
    // code to call deep_equal on each tie 
    // deep_equal on non-pointer basic types defined as == 
    // deep_equal on pointers is to check for null (nulls are equal) 
    // then dereference and deep_equal 
    // ditto for smart pointers 
    // deep_equal on vectors and other std containers is to check size, 
    // and if matches deep_equal on elements 
    } 
}; 

但是,這會增加您的負擔。但是我們的想法是增加的可靠性,正如您已經注意到的,難點在於有很多代碼和大量的錯誤點。

有沒有簡單的方法來做到這一點。

如果您的數據不是完美打包的普通舊數據而沒有指針或虛函數或任何東西,memcmp是一個壞主意。而且填充很容易滑入代碼中,從而打破了基於memcmp的平等;因爲填充中的數據狀態是未定義的,所以很難找到這樣的容器。

+0

當然,因爲小馬,會根據關係重寫序列化。 –

+0

@ n.m。這使得在這一點上'=='檢查有點荒謬,因爲兩者都是使用相同的系統編寫的。但是,我上面提到的瘋狂檢查可以幫助序列化... – Yakk