2 votes

La méthode non intrusive de sérialisation d'une classe dans Boost::Serialise rend-elle la classe sérialisable ?

J'essaie de comprendre la bibliothèque de sérialisation de Boost. (voir le tutoriel) et j'aime bien la façon non intrusive de sérialiser une classe parce que cela signifie que je peux mettre tout mon code de sérialisation dans des fichiers séparés :

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

class gps_position
{
public:
    int degrees;
    int minutes;
    float seconds;
    gps_position(){};
    gps_position(int d, int m, float s) :
        degrees(d), minutes(m), seconds(s)
    {}
};

namespace boost {
namespace serialization {

template<class Archive>
void serialize(Archive & ar, gps_position & g, const unsigned int version)
{
    ar & g.degrees;
    ar & g.minutes;
    ar & g.seconds;
}

} // namespace serialization
} // namespace boost

Bien que cette méthode fournisse une fonction 'serialise', qui peut être utilisée pour sérialiser la classe 'gps_position', je ne suis pas sûr que la classe soit elle-même un élément de la classe 'gps_position'. sérialisable (c'est-à-dire qui agit comme une primitive en termes de sérialisation/désérialisation) une fois que cette fonction a été créée, ou si je dois utiliser la méthode intrusive pour cela...

En d'autres termes, si j'ai une autre classe qui contient, par exemple, un vecteur d'instances 'gps_position', Boost saura-t-il rechercher la fonction surchargée 'serialize' dans l'espace de noms Boost::serialization correspondant à un paramètre 'gps_position' lorsque j'essaierai de sérialiser la classe parente ? Ou bien cherchera-t-il seulement explicitement une méthode "serialize" de la classe (qu'il ne trouvera pas dans ce cas) ?

Je n'ai pas trouvé la réponse à cette question dans les didacticiels et j'espérais que quelqu'un ayant de l'expérience dans l'utilisation de cette bibliothèque pourrait m'éclairer !

P.S J'hésite à "essayer" car je ne sais pas à quoi devrait ressembler l'échec (Boost va-t-il simplement sérialiser "quelque chose" ?)...

4voto

Troy Points 3598

Alors que cette méthode fournit une fonction 'serialise', qui peut être utilisée pour sérialiser la classe 'gps_position'. pour sérialiser la classe 'gps_position', je ne suis pas certain que la classe est elle-même sérialisable (c'est-à-dire qu'elle agit comme une primitive en termes de sérialisation/désérialisation) une fois que cette fonction a été créée, ou si je dois utiliser la méthode intrusive pour cela...

Oui, la classe sera sérialisée par la méthode normale d'utilisation de l'opérateur '&' avec une archive boost.serialization, quelle que soit la méthode utilisée.

En d'autres termes, si j'ai une autre classe qui contient, par exemple, un vecteur d'instances 'gps_position', Boost saura-t-il rechercher la surcharge de cette classe ? d'instances 'gps_position', Boost saura-t-il rechercher la classe surchargée surchargée de l'espace de noms Boost::serialization correspondant à un paramètre "gps_position". gps_position' lorsque j'essaie de sérialiser la classe parente ? Ou bien rechercherait-il seulement explicitement une méthode "serialize" de la classe (qu'il ne trouverait pas dans l'espace de nom Boost::serialization) ? (qu'il ne trouvera pas dans ce cas) ?

Vous devrez également fournir une fonction de sérialisation pour la classe mère. Dans laquelle vous sérialisez chaque membre de la classe de la même manière que vous l'avez fait pour la classe enfant.

P.S. J'hésite à "essayer" parce que je ne sais pas à quoi devrait ressembler l'échec (Boost va-t-il simplement sérialiser "quelque chose" ? devrait ressembler (Boost va-t-il simplement sérialiser "quelque chose" ?)...

Essayer, c'est la meilleure façon d'apprendre. Il est très probable que c'est de cette façon que toute personne cherchant à répondre à cette question aura appris après un bref regard sur la documentation.

Voici une maquette très rapide des versions intrusive et non intrusive :

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <boost/serialization/access.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

// child class serialized using intrusive

struct child
{
  std::string name;

  child() = default;

  explicit child(const std::string& name)
    : name(name)
  { }

  template <class Archive>
  void serialize(Archive& ar, const unsigned int /* version */)
  {
    ar & name;
  }
};

struct parent
{
  std::vector<child> children;

  parent() = default;

  explicit parent(const std::vector<child>& children)
    : children(children)
  { }
};

// parent class serialized using non-instrusive

namespace boost {
namespace serialization {

template <class Archive>
void serialize(Archive& ar, parent& p, const unsigned int /* version */)
{
  ar & p.children;
}

}
}

int main()
{
  parent p1 {{child("one"), child("two"), child("three")}};

  std::stringstream ss;
  boost::archive::text_oarchive oa(ss);
  oa << p1;

  parent p2;
  boost::archive::text_iarchive ia(ss);
  ia >> p2;

  for (auto& child : p2.children) {
    std::cout << child.name << "\n";
  }
}

1voto

dyp Points 19641

Alors que cette méthode fournit une fonction "serialise", qui peut être utilisée pour sérialiser la classe "gps_position", je ne suis pas sûr que la classe soit elle-même sérialisable (c'est-à-dire qu'elle se comporte comme une primitive en termes de sérialisation/désérialisation) une fois que cette fonction a été créée, ou si je dois utiliser la méthode intrusive pour cela...

Le site documentation dit :

Un type T es Serializable si et seulement si l'un des éléments suivants est vrai :

  • il s'agit d'un type primitif. [...]
  • Il s'agit d'un type de classe et l'un des éléments suivants a été déclaré conformément aux prototypes détaillés ci-dessous :
    • une fonction membre de la classe serialize
    • une fonction globale serialize
  • il s'agit d'un pointeur vers un Serializable type.
  • il s'agit d'une référence à un Serializable type.
  • il s'agit d'un tableau C++ natif de Serializable type.

En d'autres termes, si j'ai une autre classe qui contient, par exemple, un vecteur d'instances 'gps_position', Boost saura-t-il rechercher la fonction surchargée 'serialize' dans l'espace de noms Boost::serialization correspondant à un paramètre 'gps_position' lorsque j'essaierai de sérialiser la classe mère ? Ou bien cherchera-t-il seulement explicitement une méthode "serialize" de la classe (qu'il ne trouvera pas dans ce cas) ?

Un type de classe pour lequel aucune fonction membre serialize et aucune fonction globale serialize est définie (cette dernière ayant comme second paramètre une réf non-const du type de classe) ne remplit pas l'exigence de la norme Serializable concept.

Cependant, sur la même page de la documentation :

Les facilités décrites ci-dessus sont suffisantes pour implémenter la sérialisation pour tous les conteneurs STL. En fait, cela a été fait et a été inclus dans la bibliothèque.

C'est-à-dire, si vous incluez le fichier d'en-tête approprié, <boost/serialization/vector.hpp> une spécialisation du modèle vectoriel devient Serializable si son value_type es Serializable .

Comme votre classe gps_position es Serializable , a std::vector<gps_position> est également Serializable si vous avez inclus l'en-tête susmentionné. Cependant, une classe contenant un tel vecteur n'est pas automatiquement Serializable selon les règles. Il devait avoir une fonction de membre ou de non-membre. serialize :

#include <boost/serialization/vector.hpp>
struct gps_position { int i; };
struct gps_path { std::vector<gps_position> v; }

template<class Archive>
void serialize(Archive& ar, gps_position& p, const unsigned int)
{  ar & p.i;  }
// by declaring this function, `gps_position` is Serializable

template<class Archive>
void serialize(Archive& ar, gps_path& p, const unsigned int)
{  ar & p.v;  }
// as `v` is Serializable (because `gps_position` is Serializable),
// you can leave it to the boost library to serialize the individual
// elements of the vector

Remarque : la fonction ne doit pas nécessairement être globale. Comme expliqué sur la page liée de la documentation, le lookup non qualifié et l'ADL sont tous deux supportés :

Pour une portabilité maximale, incluez tous les modèles et définitions de fonctions libres dans l'espace de noms boost::serialization . Si la portabilité n'est pas un problème et que le compilateur utilisé supporte ADL (Argument Dependent Lookup), les fonctions et les modèles libres peuvent se trouver dans l'un des espaces de noms suivants :

  • boost::serialization
  • espace de nom de la classe d'archive
  • espace de nom du type sérialisé

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X