web-dev-qa-db-fra.com

Manière "appropriée" de stocker des données binaires avec C ++ / STL

En général, quelle est la meilleure façon de stocker des données binaires en C++? Autant que je sache, les options se résument à utiliser des chaînes ou des <char> vectoriels. (Je vais omettre la possibilité de char * s et malloc () s puisque je me réfère spécifiquement à C++).

Habituellement, j'utilise simplement une chaîne, mais je ne sais pas s'il y a des frais généraux qui me manquent, ou des conversions que STL fait en interne qui pourraient perturber la santé mentale des données binaires. Quelqu'un at-il des pointeurs (har) à ce sujet? Suggestions ou préférences d'une manière ou d'une autre?

45
Sean Edwards

le vecteur de l'omble est Nice car la mémoire est contigüe. Par conséquent, vous pouvez l'utiliser avec de nombreuses API C telles que les sockets berkley ou les API de fichiers. Vous pouvez effectuer les opérations suivantes, par exemple:

  std::vector<char> vect;
  ...
  send(sock, &vect[0], vect.size());

et cela fonctionnera bien.

Vous pouvez essentiellement le traiter comme tout autre tampon de caractères alloué dynamiquement. Vous pouvez numériser de haut en bas à la recherche de nombres magiques ou de motifs. Vous pouvez l'analyser partiellement en place. Pour recevoir à partir d'un socket, vous pouvez très facilement le redimensionner pour ajouter plus de données.

L'inconvénient est que le redimensionnement n'est pas terriblement efficace (redimensionner ou préallouer prudemment) et la suppression de l'avant du tableau sera également très inefficace. Si vous avez besoin, par exemple, d'afficher très fréquemment un ou deux caractères à la fois sur le devant de la structure de données, la copie dans un deque avant ce traitement peut être une option. Cela vous coûte une copie et la mémoire deque n'est pas contiguë, vous ne pouvez donc pas simplement passer un pointeur à une API C.

En bout de ligne, apprenez-en plus sur les structures de données et leurs compromis avant de plonger, mais le vecteur de l'omble est généralement ce que je vois utilisé dans la pratique générale.

41
Doug T.

Le plus gros problème avec std :: string est que la norme actuelle ne garantit pas que son stockage sous-jacent est contigu. Cependant, il n'y a aucune implémentation STL connue où la chaîne n'est pas contiguë, donc en pratique elle n'échouera probablement pas. En fait, la nouvelle norme C++ 0x va résoudre ce problème, en exigeant que std :: string utilise un tampon contigu, tel que std :: vector.

Un autre argument contre la chaîne est que son nom suggère qu'elle contient une chaîne de caractères, pas un tampon binaire, ce qui peut prêter à confusion pour ceux qui lisent le code.

Cela dit, je recommande également le vecteur.

8
Tamas Demjen

J'utilise aussi std::string Pour cela, et je n'ai jamais eu de problème avec ça.

Un "pointeur", dont je viens de recevoir un rappel précis hier dans un morceau de code: lors de la création d'une chaîne à partir d'un bloc de données binaires, utilisez la forme constructeur std::string(startIter, endIter), pas la fonction std::string(ptr, offset, length) form - ce dernier suppose que le pointeur pointe vers une chaîne de style C et ignore tout ce qui se trouve après le premier caractère zéro (il copie "jusqu'à" le length spécifié, pas length personnages).

6
Head Geek

Vous devriez certainement utiliser un conteneur de char, mais le conteneur que vous souhaitez utiliser dépend de votre application.

Les caractères ont plusieurs propriétés qui les rendent utiles pour contenir des données binaires: la norme interdit tout "remplissage" pour un type de données char, ce qui est important car cela signifie que vous n'obtiendrez pas de déchets dans votre disposition binaire. Chaque caractère est également garanti d'être exactement un octet, ce qui en fait le seul ancien type de données (POD) simple avec une largeur définie (tous les autres sont spécifiés en termes de limites supérieures et/ou inférieures).

La discussion sur le conteneur stl approprié avec lequel stocker les caractères est bien gérée par Doug ci-dessus. Lequel vous avez besoin dépend entièrement de votre cas d'utilisation. Si vous détenez simplement un bloc de données que vous parcourez, sans recherche particulière, ajout/suppression ou épissage, je préférerais vector, ce qui rend vos intentions plus claires que std :: string, que de nombreuses bibliothèques et fonctions assumeront contient une chaîne de style c terminée par un caractère nul.

3
Todd Gardner