Apakah mungkin untuk membuat serial dan deserialisasi kelas di C ++?
Saya telah menggunakan Java selama 3 tahun sekarang, dan serialisasi / deserialisasi cukup sepele dalam bahasa itu. Apakah C ++ memiliki fitur yang serupa? Apakah ada perpustakaan asli yang menangani serialisasi?
Sebuah contoh akan sangat membantu.
c++
serialization
Agusti-N
sumber
sumber
Jawaban:
The
Boost::serialization
library menangani ini agak elegan. Saya telah menggunakannya di beberapa proyek. Ada program contoh, yang menunjukkan cara menggunakannya, di sini .Satu-satunya cara asli untuk melakukannya adalah dengan menggunakan aliran. Itu pada dasarnya semua yang
Boost::serialization
perpustakaan lakukan, itu memperluas metode aliran dengan menyiapkan kerangka kerja untuk menulis objek ke format seperti teks dan membacanya dari format yang sama.Untuk tipe bawaan, atau tipe Anda sendiri dengan
operator<<
danoperator>>
ditentukan dengan benar, itu cukup sederhana; lihat FAQ C ++ untuk informasi lebih lanjut.sumber
Saya menyadari ini adalah postingan lama tetapi ini adalah salah satu postingan pertama yang muncul saat mencari
c++ serialization
.Saya mendorong siapa pun yang memiliki akses ke C ++ 11 untuk melihat sereal , perpustakaan hanya header C ++ 11 untuk serialisasi yang mendukung biner, JSON, dan XML di luar kotak. sereal dirancang agar mudah diperluas dan digunakan serta memiliki sintaks yang mirip dengan Boost.
sumber
Boost adalah saran yang bagus. Tetapi jika Anda ingin menggulung sendiri, itu tidak terlalu sulit.
Pada dasarnya Anda hanya perlu cara untuk membuat grafik objek dan kemudian menampilkannya ke beberapa format penyimpanan terstruktur (JSON, XML, YAML, apa pun). Membangun grafik semudah menggunakan algoritme objek rekursif penandaan yang layak dan kemudian mengeluarkan semua objek yang ditandai.
Saya menulis artikel yang menjelaskan sistem serialisasi yang belum sempurna (tapi tetap kuat). Anda mungkin merasa tertarik: Menggunakan SQLite sebagai Format File dalam Disk, Bagian 2 .
sumber
Saya merekomendasikan buffer protokol Google . Saya memiliki kesempatan untuk menguji coba pustaka pada proyek baru dan itu sangat mudah digunakan. Perpustakaan sangat dioptimalkan untuk kinerja.
Protobuf berbeda dari solusi serialisasi lain yang disebutkan di sini dalam arti bahwa itu tidak membuat serialisasi objek Anda, melainkan menghasilkan kode untuk objek yang serialisasi sesuai dengan spesifikasi Anda.
sumber
Sejauh perpustakaan "built-in" pergi,
<<
dan>>
telah dipesan khusus untuk serialisasi.Anda harus mengganti
<<
untuk mengeluarkan objek Anda ke beberapa konteks serialisasi (biasanya sebuahiostream
) dan>>
untuk membaca data kembali dari konteks itu. Setiap objek bertanggung jawab untuk mengeluarkan objek turunannya yang teragregasi.Metode ini berfungsi dengan baik selama grafik objek Anda tidak berisi siklus.
Jika ya, maka Anda harus menggunakan perpustakaan untuk menangani siklus tersebut.
sumber
<<
operator yang diimplementasikan digunakan untuk mencetak representasi teks yang dapat dibaca manusia dari objek, yang seringkali bukan yang Anda inginkan untuk serialisasi.<<
generikostream
, coba tentukan untuk aliran file.<<
untuk mengeluarkan objek Anda ke beberapa konteks serialisasi ... Setiap objek bertanggung jawab untuk mengeluarkannya ..." - pertanyaannya adalah tentang bagaimana menghindari keharusan menulis itu dengan susah payah untuk setiap objek: berapa banyak yang bisa bahasa atau perpustakaan membantu?Boost :: serialization adalah pilihan yang bagus, tetapi saya menemukan proyek baru: Cereal yang menurut saya jauh lebih elegan! Saya sangat menyarankan untuk menyelidikinya.
sumber
Anda dapat memeriksa protokol amef , contoh pengkodean C ++ di amef akan seperti,
//Create a new AMEF object AMEFObject *object = new AMEFObject(); //Add a child string object object->addPacket("This is the Automated Message Exchange Format Object property!!","adasd"); //Add a child integer object object->addPacket(21213); //Add a child boolean object object->addPacket(true); AMEFObject *object2 = new AMEFObject(); string j = "This is the property of a nested Automated Message Exchange Format Object"; object2->addPacket(j); object2->addPacket(134123); object2->addPacket(false); //Add a child character object object2->addPacket('d'); //Add a child AMEF Object object->addPacket(object2); //Encode the AMEF obejct string str = new AMEFEncoder()->encode(object,false);
Decoding di java akan seperti,
string arr = amef encoded byte array value; AMEFDecoder decoder = new AMEFDecoder() AMEFObject object1 = AMEFDecoder.decode(arr,true);
Implementasi Protokol memiliki codec untuk C ++ dan Java, yang menarik adalah dapat mempertahankan representasi kelas objek dalam bentuk pasangan nilai nama, saya memerlukan protokol serupa di proyek terakhir saya, ketika saya kebetulan menemukan protokol ini, saya sebenarnya memodifikasi pustaka dasar sesuai dengan kebutuhan saya. Semoga ini bisa membantu Anda.
sumber
Saya merekomendasikan menggunakan serialisasi boost seperti yang dijelaskan oleh poster lain. Berikut adalah tutorial terperinci yang bagus tentang cara menggunakannya yang melengkapi tutorial peningkatan dengan baik: http://www.ocoudert.com/blog/2011/07/09/a-praktis-guide-to-c-serialization/
sumber
Sweet Persist adalah satu lagi.
Dimungkinkan untuk membuat serial ke dan dari stream dalam format XML, JSON, Lua, dan biner.
sumber
Saya sarankan melihat ke pabrik Abstrak yang sering digunakan sebagai dasar untuk serialisasi
Saya telah menjawab dalam pertanyaan SO lain tentang pabrik C ++. Silakan lihat di sana jika pabrik fleksibel menarik. Saya mencoba menjelaskan cara lama dari ET ++ untuk menggunakan makro yang telah bekerja sangat baik untuk saya.
ET ++ adalah proyek untuk mem-port MacApp lama ke C ++ dan X11. Dalam upaya itu Eric Gamma dll mulai memikirkan Pola Desain . ET ++ berisi cara otomatis untuk serialisasi dan introspeksi saat runtime.
sumber
Jika Anda menginginkan kinerja yang sederhana dan terbaik dan tidak peduli dengan kompatibilitas data mundur, coba HPS , ini ringan, jauh lebih cepat daripada Boost, dll, dan jauh lebih mudah digunakan daripada Protobuf, dll.
Contoh:
std::vector<int> data({22, 333, -4444}); std::string serialized = hps::serialize_to_string(data); auto parsed = hps::parse_from_string<std::vector<int>>(serialized);
sumber
Ini adalah pustaka serializer sederhana yang saya buat. Ini hanya header, c11 dan memiliki contoh untuk membuat serial tipe dasar. Ini satu untuk peta ke kelas.
https://github.com/goblinhack/simple-c-plus-plus-serializer
#include "c_plus_plus_serializer.h" class Custom { public: int a; std::string b; std::vector c; friend std::ostream& operator<<(std::ostream &out, Bits my) { out << bits(my.t.a) << bits(my.t.b) << bits(my.t.c); return (out); } friend std::istream& operator>>(std::istream &in, Bits my) { in >> bits(my.t.a) >> bits(my.t.b) >> bits(my.t.c); return (in); } friend std::ostream& operator<<(std::ostream &out, class Custom &my) { out << "a:" << my.a << " b:" << my.b; out << " c:[" << my.c.size() << " elems]:"; for (auto v : my.c) { out << v << " "; } out << std::endl; return (out); } }; static void save_map_key_string_value_custom (const std::string filename) { std::cout << "save to " << filename << std::endl; std::ofstream out(filename, std::ios::binary ); std::map< std::string, class Custom > m; auto c1 = Custom(); c1.a = 1; c1.b = "hello"; std::initializer_list L1 = {"vec-elem1", "vec-elem2"}; std::vector l1(L1); c1.c = l1; auto c2 = Custom(); c2.a = 2; c2.b = "there"; std::initializer_list L2 = {"vec-elem3", "vec-elem4"}; std::vector l2(L2); c2.c = l2; m.insert(std::make_pair(std::string("key1"), c1)); m.insert(std::make_pair(std::string("key2"), c2)); out << bits(m); } static void load_map_key_string_value_custom (const std::string filename) { std::cout << "read from " << filename << std::endl; std::ifstream in(filename); std::map< std::string, class Custom > m; in >> bits(m); std::cout << std::endl; std::cout << "m = " << m.size() << " list-elems { " << std::endl; for (auto i : m) { std::cout << " [" << i.first << "] = " << i.second; } std::cout << "}" << std::endl; } void map_custom_class_example (void) { std::cout << "map key string, value class" << std::endl; std::cout << "============================" << std::endl; save_map_key_string_value_custom(std::string("map_of_custom_class.bin")); load_map_key_string_value_custom(std::string("map_of_custom_class.bin")); std::cout << std::endl; }
Keluaran:
map key string, value class ============================ save to map_of_custom_class.bin read from map_of_custom_class.bin m = 2 list-elems { [key1] = a:1 b:hello c:[2 elems]:vec-elem1 vec-elem2 [key2] = a:2 b:there c:[2 elems]:vec-elem3 vec-elem4 }
sumber
Saya menggunakan template berikut untuk mengimplementasikan serialisasi:
template <class T, class Mode = void> struct Serializer { template <class OutputCharIterator> static void serializeImpl(const T &object, OutputCharIterator &&it) { object.template serializeThis<Mode>(it); } template <class InputCharIterator> static T deserializeImpl(InputCharIterator &&it, InputCharIterator &&end) { return T::template deserializeFrom<Mode>(it, end); } }; template <class Mode = void, class T, class OutputCharIterator> void serialize(const T &object, OutputCharIterator &&it) { Serializer<T, Mode>::serializeImpl(object, it); } template <class T, class Mode = void, class InputCharIterator> T deserialize(InputCharIterator &&it, InputCharIterator &&end) { return Serializer<T, Mode>::deserializeImpl(it, end); } template <class Mode = void, class T, class InputCharIterator> void deserialize(T &result, InputCharIterator &&it, InputCharIterator &&end) { result = Serializer<T, Mode>::deserializeImpl(it, end); }
Berikut
T
adalah tipe yang ingin Anda serialisasiMode
adalah tipe dummy untuk membedakan antara berbagai jenis serialisasi, mis. integer yang sama dapat diserialkan sebagai little endian, big endian, varint, dll.Secara default,
Serializer
mendelegasikan tugas ke objek yang diserialisasi. Untuk tipe bawaan, Anda harus membuat spesialisasi template dariSerializer
.Templat fungsi kenyamanan juga disediakan.
Misalnya serialisasi little endian dari unsigned integers:
struct LittleEndianMode { }; template <class T> struct Serializer< T, std::enable_if_t<std::is_unsigned<T>::value, LittleEndianMode>> { template <class InputCharIterator> static T deserializeImpl(InputCharIterator &&it, InputCharIterator &&end) { T res = 0; for (size_t i = 0; i < sizeof(T); i++) { if (it == end) break; res |= static_cast<T>(*it) << (CHAR_BIT * i); it++; } return res; } template <class OutputCharIterator> static void serializeImpl(T number, OutputCharIterator &&it) { for (size_t i = 0; i < sizeof(T); i++) { *it = (number >> (CHAR_BIT * i)) & 0xFF; it++; } } };
Kemudian untuk membuat serial:
std::vector<char> serialized; uint32_t val = 42; serialize<LittleEndianMode>(val, std::back_inserter(serialized));
Untuk deserialisasi:
uint32_t val; deserialize(val, serialized.begin(), serialized.end());
Karena logika iterator abstrak, ia harus bekerja dengan iterator apa pun (misalnya, iterator aliran), penunjuk, dll.
sumber