IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

A propos de std::streambuf


Sujet :

C++

Vue hybride

bowow A propos de std::streambuf 14/05/2015, 01h04
foetus Je ne suis pas expert de... 14/05/2015, 01h51
jo_link_noir C'est dommage que... 14/05/2015, 02h26
foetus En regardant les exemples sur... 14/05/2015, 02h38
bowow foetus, contrairement à ce... 14/05/2015, 02h57
jo_link_noir Pas à ma connaissance. Si les... 14/05/2015, 06h23
bowow Ouais en fait, j'avais posté... 14/05/2015, 11h09
Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2012
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2012
    Messages : 56
    Par défaut A propos de std::streambuf
    Bonsoir,

    j'ai un problème avec l'utilisation de std::streambuf. Apparemment, il travaille avec des char*, mais visiblement, j'ai du mal à gérer la mémoire dans mon projet.

    Admettons le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    template <typename T>
    inline std::string read(std::ifstream& ifs, const T& offset, const T& size)
    {
    	std::streambuf *pbuf = ifs.rdbuf();
    	char* contents = new char[size + 1];
    	pbuf->pubseekoff(offset, ifs.beg);
    	pbuf->sgetn(contents, size);
    	contents[size] = '\0';
    	std::string datas(contents);
    	delete[] contents;
    	delete pbuf;
    	return datas;
    }
    Cette fonction est appelée des millions de fois , la désallocation ne se semble pas se dérouler correctement, ma mémoire RAM finit par saturer.. J'ai du oublier un détail.

    Merci d'avance pour vos réponses.

  2. #2
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 759
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 759
    Par défaut
    Je ne suis pas expert de std::streambuf mais essayes d'éviter les allocations et les desallocations.

    Pour
    • La variable contents passe là en static ou en global et fixe sa taille avec la plus grande taille possible (tu dois la connaître)
    • La variable pbuf là c'est inévitable, à moins d'avoir une seule variable ifs (puisqu'on prend son pointeur sur son objet interne)
    • Pour ta valeur de retour, il me semble qu'un const std::string& évite des recopies inutiles. Mais je pense qu'un const est trop limitant.


    Par contre, il semble te manquer un ifs.close(); juste avant la ligne 10

  3. #3
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    C'est dommage que l'application ne plante pas (elle devrait). Mais un outil d'analyse (asan, valgrind, ...) aurait probablement relevé l'erreur.
    La ligne 11 est de trop. Le pbuf est détruit et ifs n'en est même pas informé !

    Tu peux aussi te passer complètement du buffer intermédiaire.
    Depuis C++11, la mémoire d'un std::string est garantit continue, ce qui permet de remplacer content par &datas[0] (après application de std::string::resize).
    Par contre, il y a toujours le memset dû au resize.

    J'ai une fonction de lecture de fichier un peu sioux. Comme aucune donnée n'est présente dans le buffer du streambuf, tout le contenu est directement écrit dans le buffer donné à sgetn (pas d'intermédiaire). Remplacer le buffer interne du streambuf permet aussi de l'empêcher d'en allouer un.

    @foetus: pourquoi vouloir fermer le fichier ? La fonction ne s'appelle pas read_and_close

  4. #4
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 759
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 759
    Par défaut
    Citation Envoyé par jo_link_noir Voir le message
    @foetus: pourquoi vouloir fermer le fichier ? La fonction ne s'appelle pas read_and_close
    En regardant les exemples sur cplusplus.com ici (qui est très proche du code de bowow) et

  5. #5
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2012
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2012
    Messages : 56
    Par défaut
    foetus, contrairement à ce que tu peux penser, je ne peux pas prédire la taille du buffer à l'avance, les données sont très très denses, je ne peux donc pas les lire, d'ou mon allocation dynamique. Comme cette fonction est appelée des milliards de fois, le fichier reste ouvert jusqu'à la lecture complète du fichier à partir des offsets sauvegardés dans un vecteur de structure.

    jo_link_noir, merci bien, comme toujours! Bon j'ai remplacé mon code par celui-ci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <typename T>
    std::string read(std::ifstream& ifs, const T& offset, const T& size)
    {
    	std::string datas;
    	datas.resize(size);
    	std::streambuf *pbuf = ifs.rdbuf();
    	pbuf->pubseekoff(offset, ifs.beg);
    	pbuf->sgetn(&datas[0], size);
     
    	return datas;
    }
    je récupère bien mes chaines de caractères et la RAM me dit merci.

    Par contre, je recherche à supprimer des '\n' en plein milieu de la chaine de caractères, existe-t-il un méthode adaptée pour ça? j'avais pensé faire une fonction un peu dérivée de celle du dessus:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    template <typename T>
    std::string read_char(std::ifstream& ifs, const T& offset, const T& size)
    {
    	std::string datas;
    	std::streambuf *pbuf = ifs.rdbuf();
    	pbuf->pubseekoff(offset, ifs.beg);
    	do
    	{
    		char c = pbuf->sgetc();
    		if (c != '\n')
    		  datas.push_back(c);
     
    	} while (pbuf->snextc() != '>');
     
    	return datas;
    }

  6. #6
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    Citation Envoyé par bowow Voir le message
    Par contre, je recherche à supprimer des '\n' en plein milieu de la chaine de caractères, existe-t-il un méthode adaptée pour ça?
    Pas à ma connaissance. Si les sauts de lignes sont peu nombreux, peut-être une boucle sur sgetn() et std::remove(..., '\n') ?

    Attention avec read_char. Avec resize, il ne faut pas insérer en fin, mais modifier les valeurs du tableaux (ou utiliser std::string::reserve + insert/push_back).
    La ligne 15 n'a pas d'effet en l'état: resize() joue sur la valeur de size(). Si on lui donne la valeur de size(), alors il n'y a rien à faire.
    Concernant la boucle, je ne comprends pas ce que vient faire la comparaison sur '>' ? Un parser html ?

    Aussi, tu ne fais pas de vérification d'erreur de lecture ?

  7. #7
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2012
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2012
    Messages : 56
    Par défaut
    Ouais en fait, j'avais posté le code à 3h du mat', sans vraiment tester, alors qu'un simple push_back est plus adapté et redimensionne automatiquement. J'ai réédité mon poste initial.

    je testerais bien ta méthode avec sgetn et std::remove, pour voir et comparer. (je bench pas mal, je recherche toujours les moindres petites optimisations).

    Pour les erreurs de lecture, je ne vois pas trop ou tu veux en venir, vérifier que c != null ?

  8. #8
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    Citation Envoyé par bowow Voir le message
    Pour les erreurs de lecture, je ne vois pas trop ou tu veux en venir, vérifier que c != null ?
    Vérifier par exemple qu'il n'y a plus rien à lire ou qu'il n'est plus possible de lire (il n'y a pas de distinction entre la fin de fichier et une erreur, il faut regarder errno pour ça).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    using traits = stream_buf::traits_type;
    const auto eof = traits::eof();
    auto c = sb->sgetc();
     
    while (!traits::eq_int_type(c, eof)) {
        ...
        c = sb->snextc();
    }

    Comme j'y pense, que devient la chaîne retournée par read et read_char ? Si elle peut être réutilisée, il est préférable de la fournir en référence aux fonctions pour ne pas allouer systématiquement la mémoire quand resize/reserve est appelé.

Discussions similaires

  1. A propos de std::istreambuf_iterator<>
    Par bowow dans le forum C++
    Réponses: 2
    Dernier message: 29/04/2015, 00h15
  2. Réponses: 18
    Dernier message: 19/08/2011, 16h21
  3. question à propos d'un std::vector encapsuler
    Par Date90 dans le forum C++
    Réponses: 2
    Dernier message: 05/04/2009, 15h20
  4. A propos de std::ostrstream
    Par camboui dans le forum SL & STL
    Réponses: 20
    Dernier message: 08/01/2009, 18h21
  5. A propos du composant DBGrid
    Par _Rico_ dans le forum C++Builder
    Réponses: 2
    Dernier message: 24/07/2002, 09h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo