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

SL & STL C++ Discussion :

for_each / copy / ostream_iterator / mem_fun


Sujet :

SL & STL C++

  1. #1
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut for_each / copy / ostream_iterator / mem_fun
    Bonjour, et merci de lire ce post.

    Voici mon problème : j'ai un conteneur orienté de pointeurs d'objets de classe A, quelque chose comme :
    la classe A peut être définie comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class A
    {
    public : 
       A();
       ~A();
       std::string& getText();
    }
    Et je voudrais concaténer ce que me renvoient les fonctions getText() des objets contenus dans la liste.

    Autrement dit, ce que je voudrais faire c'est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    std::ostringstream oss;
    for(std::list<A*>::iterator it = list.begin(); it != list.end(); it++)
    {
       oss << it->getText();
    }
    Maintenant, je me demandais deux choses :
    1 - s'il n'existait pas un moyen de faire la même chose en utilisant mem_fun, un ostream_iterator et std::copy ?
    2 - si une telle méthode existait, serait-elle plus rapide que celle-ci ?

    Merci de votre aide

  2. #2
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    1- Ca risque d'être un peu compliqué avec la STL ; avec boost je pense que ce serait déjà un peu plus simple.

    2- Absolument pas, la seule différence est que tu auras une écriture plus concise (enfin ça peut aussi être le contraire, à trop vouloir utiliser la STL on a tendance à faire n'importe quoi). Tout ce que font les diverses structures et fonctions de ce genre dans la STL, c'est cacher les boucles ou les opérateurs << que tu aurais écrit toi-même.

  3. #3
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    Merci beaucoup pour cette réponse.

    Tant pis pour moi, j'aurais bien voulu apprendre quelque chose.

    Hélas je ne peux pas utiliser boost dans ce projet-ci, ça m'aurait permis de m'y plonger un peu plus.

    J'ai finalement opté pour un std::for_each et un foncteur hand-made que j'ai localisé dans mon objet A.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class A
    {
    public : 
       A();
       ~A();
    public :
       std::string& getText();
    public :
       class TextSerializer
      {
        ...
      };
    };
    Il me semble que c'est une bonne chose de faire un Foncteur, car je serais amené à utiliser plusieurs fois cette concaténation depuis divers endroits.

    Il me semble que c'est une bonne chose de localiser ce bout de code dans ma classe A, car cela me permettra de le modifier simplement si je venais à changer ma fonction A::getText();

    Qu'en pensez-vous ?

    Merci de vos réponses.

    Bonne journée.

  4. #4
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Le laisser là est une idée correcte si uniquement la classe A se sert de TextSerializer.

    Sinon, fais en un foncteur ou une fonction libre (du genre std::for_each, std::transform, ...).

    Tu es dans lequel de ces cas ?

  5. #5
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par Feriaman Voir le message
    Merci beaucoup pour cette réponse.

    Tant pis pour moi, j'aurais bien voulu apprendre quelque chose.
    Bonjour,
    tu pourrai utiliser accumulate

    Code C++ : 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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #include <algorithm>
    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <string>
    #include <numeric>
     
     
    class A
    {
    public : 
    	A(std::string s):m_s(s){};
    	~A(){};
    	const std::string& getText()const {return m_s;};
    private:
    	std::string m_s;
    };
    std::string concat(const std::string & s,const A * a) {return s+a->getText();};
     
    int main(int argc, char** argv)
    {
    	std::vector<A*> vecttest;
    	vecttest.push_back(new A("test1"));
    	vecttest.push_back(new A("test2"));
    	vecttest.push_back(new A("test3"));
    	std::string s = std::accumulate(vecttest.begin(),vecttest.end(),std::string(""),&concat);
    std::cout<<s<<std::endl;
    return 0;
    }

  6. #6
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    Le laisser là est une idée correcte si uniquement la classe A se sert de TextSerializer.

    Sinon, fais en un foncteur ou une fonction libre (du genre std::for_each, std::transform, ...).

    Tu es dans lequel de ces cas ?
    Merci de cette réponse.

    Il se trouve que pour sérializer A, il faut faire appel à la fonction getText(), il m'est donc impossible d'utiliser le TextSerializer sur un autre type d'objet.

    Après, je pourrais aussi faire dépendre ma classe TextSerializer d'un pointeur fonction membre, auquel cas je pourrais effectivement le rendre indépendant.

    Ou alors je pourrais faire une classe Serializable dont dériverait ma classe A, et à ce moment là TextSerializer dépendrait directement de Serializable.

    Aucun de ces deux cas ne convient à mon application.

  7. #7
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    Citation Envoyé par Mongaulois Voir le message
    Bonjour,
    tu pourrai utiliser accumulate
    Class, je regarde de suite.

  8. #8
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par Feriaman Voir le message
    Class, je regarde de suite.
    Par contre, pour les perfs je ne garantie rien.

  9. #9
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    Citation Envoyé par Mongaulois Voir le message
    Par contre, pour les perfs je ne garantie rien.
    Je ne crois pas que je vais utiliser cela finalement.
    Mais merci tout de même de m'avoir proposé cette solution, ça m'a permis d'y réfléchir.

    En particulier, le fait de "cacher" l'appel de getText() dans la fonction concat ne me semble pas raisonnable. Il me semble qu'une fonction aussi spécifiquement liée à la définition d'un objet devrait lui appartenir.

    On voit bien l'évolution biaisée d'un tel code : le jour où j'ai d'autres infos que le getText() à concaténer, je rajoute une fonction, puis une autre ... et finalement quelqu'un finira bien par en faire une qui ne sert plus à concaténer, mais juste à appeler une fonction de mes objets.

    En tout cas, cette réflexion méritait d'être menée, et je remercie de m'avoir permis de le faire.

  10. #10
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    T'as qu'à changer le nom, ou bien créer une fonction Format() qui te retourne la chaine avec tout le nécessaire concaténé, concaténant le nom, le prénom et l'âge du capitaine ...

  11. #11
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    Citation Envoyé par Alp Voir le message
    T'as qu'à changer le nom, ou bien créer une fonction Format() qui te retourne la chaine avec tout le nécessaire concaténé, concaténant le nom, le prénom et l'âge du capitaine ...
    J'ai un peu peur de ça :
    Imaginons que je veuille par exemple implémenter 2 fonctions A::GetText() différentes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class A
    {
        public :
            std::string getNames();
            std::string getFullInfos();
    }
    La première sert à lister les noms et la seconde à lister les infos complètes.
    je coderais à ce moment deux fonctions libres :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    concatNames();
    concatFullInfos();
    Puis un jour j'ai besoin de vérifier l'intégrité de tous mes objets et je veux récupérer les logs, rien ne m'empèche de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class A
    {
        public :
            std::string getNames();
            std::string getFullInfos();
            std::string checkIntegrity();
    };
    concatNames();
    concatFullInfos();
    checkIntegrityAndConcatResults();
    Déjà c'est limite.

    Et finalement, un jour, je serais tenté de coder ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class A
    {
        public :
            std::string getNames();
            std::string getFullInfos();
            std::string checkIntegrity();
            std::string display();
    };
    concatNames();
    concatFullInfos();
    checkIntegrityAndConcatResults();
    displayall();
    Et d'utiliser mon accumulate pour faire quelque chose qui n'accumule rien du tout.

    Bon bien sur, sorti du contexte, cette réflexion n'a peut être pas tout son sens. Je crois qu'on peu résumer en disant quelque chose comme : on ne devrait utiliser accumulate que pour des cas où on cherche à sommer les objets eux-même et non pas une de leur caractéristiques.

    Bien sur, c'est un raisonnement à chaud, j'aurais peut-être un autre avis lpus tard.

  12. #12
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par Feriaman Voir le message
    Je ne crois pas que je vais utiliser cela finalement.
    Mais merci tout de même de m'avoir proposé cette solution, ça m'a permis d'y réfléchir.

    En particulier, le fait de "cacher" l'appel de getText() dans la fonction concat ne me semble pas raisonnable. Il me semble qu'une fonction aussi spécifiquement liée à la définition d'un objet devrait lui appartenir.

    On voit bien l'évolution biaisée d'un tel code : le jour où j'ai d'autres infos que le getText() à concaténer, je rajoute une fonction, puis une autre ... et finalement quelqu'un finira bien par en faire une qui ne sert plus à concaténer, mais juste à appeler une fonction de mes objets.

    En tout cas, cette réflexion méritait d'être menée, et je remercie de m'avoir permis de le faire.
    Aprés c'est une philosophie. Pour éviter cela, le foncteur pourrai être static a ta class


    Code C++ : 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
    17
    18
    19
    20
    21
    22
    23
    class A
    {
    public : 
    	A(std::string s):m_s(s){};
    	~A(){};
    	const std::string& getText()const {return m_s;};
     
     
    static std::string concatText(const std::string & s,const A * a) {return s+a->getText();};
     
    private:
    	std::string m_s;
    };
    int main(int argc, char** argv)
    {
    	std::vector<A*> vecttest;
    	vecttest.push_back(new A("test1"));
    	vecttest.push_back(new A("test2"));
    	vecttest.push_back(new A("test3"));
    	std::string s = std::accumulate(vecttest.begin(),vecttest.end(),std::string(""),&A::concatText);
    std::cout<<s<<std::endl;
    return 0;
    }

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. map, copy et ostream_iterator
    Par gbdivers dans le forum SL & STL
    Réponses: 2
    Dernier message: 28/07/2012, 00h30
  2. mem_fun et for_each
    Par EmlTakeo dans le forum SL & STL
    Réponses: 7
    Dernier message: 01/08/2008, 17h15
  3. Protéger une disquette contre la copie
    Par benzaza dans le forum Assembleur
    Réponses: 20
    Dernier message: 16/01/2005, 10h42
  4. Copie de fichier
    Par Bjorn dans le forum C
    Réponses: 4
    Dernier message: 11/06/2002, 15h23
  5. Peux t'on créer une copie locale de l'objet partagé?
    Par Anonymous dans le forum CORBA
    Réponses: 8
    Dernier message: 16/04/2002, 16h20

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