C++ Boost

序列化

序列化包裝器


二進位物件
陣列
BOOST_STRONG_TYPEDEF
集合大小
名稱-值對
組合
有時為了支援某些底層資料的序列化,建立一個臨時物件會比較方便。這允許封存類別針對此類型定義特殊處理方式。程式庫包含數種類似用途的類型。

某些封存需要以特殊方式處理包裝器,因此這些包裝器類別的 is_wrapper 特性會設定為 true。

二進位物件

二進位物件只是一系列以原始二進位資料儲存的位元組。這通常用於大量的「輕量級」資料,例如像素圖或嵌入式二進位檔案。標頭檔 binary_object.hpp 包含建構函式

boost::serialization::binary_object(void * t, size_t size);
boost::serialization::make_binary_object(void * t, size_t size);
它會建構一個可以像其他物件一樣被序列化的臨時二進位物件。其預設序列化方式是使用封存類別的原生函式 save_binaryload_binary。請注意,它不會配置任何儲存空間或建立任何物件。其唯一目的是將資料大小和位址作為一對傳遞給封存類別。

陣列

陣列是連續的同質資料類型序列,例如內建 C 陣列、boost::array<T>std::vector<T>。此包裝器的目的是支援提供針對相同類型連續物件序列進行最佳化序列化的封存類型(例如二進位封存)。標頭檔 array.hpp 包含函式

template <T>
boost::serialization::make_array(T* t, std::size_t size);
它會建構一個臨時的 array 物件

template<class T>
class array
{
public:    
    typedef T value_type;
    array(value_type* t, std::size_t s);
    value_type* address() const;
    std::size_t count() const;
};
它可以像其他物件一樣被序列化。其預設序列化方式是序列化每個陣列元素。請注意,它不會配置任何儲存空間或建立任何物件。其唯一目的是將資料類型、大小和位址傳遞給封存類別。可以為連續同質資料陣列提供最佳化實作的封存類型應覆載 array 的序列化。

BOOST_STRONG_TYPEDEF

另一個序列化包裝器的例子是BOOST_STRONG_TYPEDEF 樣板。序列化程式庫使用這些樣板將特定種類的整數(例如 object_id、版本等)傳遞給封存類別。由於這些整數現在可以根據其類型加以區分,因此 XML 封存可以對這些類型套用特殊處理。例如,版本號碼會以「version=12」的形式呈現為 XML 屬性。在沒有任何特定覆載的情況下,這些類型會自動轉換為底層整數類型,因此其他封存不需要 XML 封存使用的特殊覆載。

集合大小

一個強類型定義的例子是標頭檔 collection_size_type.hpp 中的 collection_size_type。 這個類型應該用於序列化 C++ 集合的大小,以便存檔可以選擇最佳的整數表示法來序列化集合大小。這是必要的,因為儘管 std::size_t 保證是一個足夠大的整數類型,可以在特定平台上表示集合的大小,但存檔可能希望以不同於此類型的方式序列化大小。例如,collection_size_type 可以在可攜式二進位存檔中序列化為可變長度整數。

名稱-值對

XML 存檔呈現出一種特殊情況。XML 格式具有巢狀結構,可以很好地映射到序列化系統使用的「遞迴類別成員訪問器」模式。然而,XML 與其他格式的不同之處在於它需要為每個類別資料成員命名。我們的目標是在類別序列化規範中添加此資訊,同時仍然允許序列化程式碼與任何存檔一起使用。

我們的解決方案是將要序列化的類別成員包裝在一個名稱-值對中。 這個結構定義在 nvp.hpp 中。它只是對資料成員的參考,以及一個指向 const char * 的指標,該指標對應於 XML 名稱。它實現了名稱-值對的預設序列化函式。此預設操作是忽略項目名稱並以正常方式序列化資料值。對於沒有為名稱-值對做出任何特殊規定的存檔類別,這是序列化名稱-值對時將調用的操作。因此,將資料值包裝到名稱-值對中,在與沒有為此包裝器做出特殊規定的存檔一起使用時,將沒有任何影響。

xml 存檔類別包含類似於以下的程式碼:


// special treatment for name-value pairs.
template<class T>
xml_oarchive & operator&(const boost::serialization::nvp<T> & t)
{
    // write an xml start tag
    start_tag(t.name());

    // serialize the data as usual
    *this & t.value();

    // write an xml end tag
    end_tag(t.name());
}
指定為 XML 資料項目名稱最明顯且最方便的名稱是——驚喜!——C++ 類別資料成員的名稱。所以我們的序列化程式碼看起來像這樣:

ar & make_nvp("my_variable", my_variable);
為了簡化輸入並提高可讀性,定義了一個巨集,以便我們可以這樣寫:

ar & BOOST_SERIALIZATION_NVP(my_variable);
類似地,存在一個巨集定義,允許我們這樣寫:

BOOST_SERIALIZATION_BASE_OBJECT_NVP(my_base_class)
請注意,這些巨集必須在類別的命名空間中使用,並且在參數中不要限定命名空間。

demo_gps.hpp 包含所有資料成員的 NVP 包裝器。demo_xml.cpp 將資料儲存和載入到 XML 存檔中。這裡是與我們的教學範例相對應的 XML 存檔範例。

組合

包裝器應該設計成可以根據需要組合。例如,要將二進位資料作為名稱-值對傳遞,請使用:

ar & make_nvp("named_binary_object", make_binary_object(address, size));

© Copyright Robert Ramey 2002-2004。依據 Boost 軟體授權條款 1.0 版散佈。(請參閱隨附檔案 LICENSE_1_0.txt 或複製於 https://boost.dev.org.tw/LICENSE_1_0.txt)