Bonjour à tous.
Je souhaite sérialiser une structure d’arbre la relation entre les différents noeuds est assurée par des pointeurs nus (ie T*) et la mémoire est gérée par unvector<unique_ptr<T>>
à coté.
Pour assurer la sérialisation, je teste boost::serialization et les premières expérimentations m’impressionnent. La bibliothqèe arrive à reconstruire une structure d’arbre en mémoire avec assez peu d’effort.
Le problème, c’est que les pointeurs nus deviennent responsable de la mémoire ! Et ca c’est pas cool du tout. Il faut donc re-transférer la gestion de la mémoire au vecteur qui va bien.
J’ai une solution illustrée dans le code ci dessous. En guise de test, je créer 10 objets de A et je vais stocker un tableau qui contient 2 fois chaque objet sous forme de pointeur. Ca sert à simuler les noeuds partagés que j’ai dans mon arbre. Lors de la relecture, je vais créer après avoir tout lu, un unique_pointeur pour chaque pointeur lu, en prenant garde d’éviter d’en créer si l’adresse est déjà présente dans la liste (pour éviter un double delete).
Le seul problème que je vois, c’est qu’entre la lecture du tableau et la création des unique_ptr
, la mémoire n’est géré par personne. Mais je survirai
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | #include <boost/archive/text_iarchive.hpp> #include <boost/archive/text_oarchive.hpp> #include <boost/serialization/export.hpp> #include <boost/serialization/serialization.hpp> #include <boost/serialization/split_member.hpp> #include <boost/serialization/vector.hpp> #include <iostream> #include <vector> #include <fstream> #include <memory> struct A{ int i; A(int n):i(n){} template <class Archive> void serialize(Archive &ar, const unsigned int version) { ar &i; } private: friend class boost::serialization::access; A() = default; }; struct Test { std::vector<std::unique_ptr<A>> mem_store; std::vector<A*> to_store; Test() = default; Test(bool) { for (int i = 0; i < 10; ++i) { mem_store.push_back(std::make_unique<A>(i)); } for (int n = 0; n < 2; ++n) { for (auto const &ptr : mem_store) { to_store.push_back(ptr.get()); } } } private: friend class boost::serialization::access; template <class Archive> void save(Archive &ar, const unsigned int version) const { ar &to_store; } template <class Archive> void load(Archive &ar, const unsigned int version) { ar &to_store; for (auto ptr_raw : to_store) { if (std::find_if(mem_store.begin(), mem_store.end(), [ptr_raw](auto const &stored_ptr) { return ptr_raw == stored_ptr.get(); }) == mem_store.end()) { mem_store.push_back(std::unique_ptr<A>(ptr_raw)); } } } BOOST_SERIALIZATION_SPLIT_MEMBER() }; BOOST_CLASS_EXPORT_GUID(Test, "Test"); BOOST_CLASS_EXPORT_GUID(A, "A"); void store() { // create and open a character archive for output std::ofstream ofs("arxiv"); boost::archive::text_oarchive oa(ofs); Test t{true}; oa << t; } void reload() { // create and open an archive for input std::ifstream ifs("arxiv"); boost::archive::text_iarchive ia(ifs); Test t; ia >> t; for (auto ptr_raw : t.to_store) { std::cout << ptr_raw <<" "<<ptr_raw->i<<"\n"; } std::cout << "FINAl SIZE " << t.mem_store.size() << "\n"; } int main() { store(); reload(); return 0; } |
Valgrind est content, ca marche, mais est ce que c’est juste ? Y’a-t-il autre chose (un bug/une faille) que j’aurai loupé ?
Merci ! David