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 :

Problème de construction avec la STL


Sujet :

SL & STL C++

  1. #1
    Membre régulier Avatar de gelam
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2003
    Messages : 69
    Points : 74
    Points
    74
    Par défaut Problème de construction avec la STL
    Bonjour,
    Je suis en train de faire quelques essais avec la STL. J'utilise VC6 et je constate qqch de bizarre...
    Lorsque je compile le code suivant tout se passe bien :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main(){
      int tab[]={11,22,33,44,55} ;
      vector<int> conteneur(tab,tab+5) ;
    }
    alors qu'avec ce code j'ai une erreur de compilation

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main(){
      int tab[]={11,22,33,44,55} ;
      deque<int> conteneur(tab,tab+5) ;
    }
    Dans la doc vector et deque offrent tous deux un constructeur paramétré avec deux itérateurs.
    Que se passe-t-il ?
    J'ai de la peine à croire qu'il y ait un bug dans la STL ???

    Merci d'avance pour vos réponses
    Avez-vous remarqué les progrès que fait l'ignorance?
    [Tristan Bernard ]

  2. #2
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 751
    Points : 10 670
    Points
    10 670
    Billets dans le blog
    3
    Par défaut
    J'ai de la peine à croire qu'il y ait un bug dans la STL ???
    et pourtant...
    http://c.developpez.com/faq/cpp/?pag...LEMES_stl_vcpp
    tu as installé le dernier Service Pack ?
    Le mieux est de passer à VC++ 7.1

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    un itérateur n'est pas un pointeur.

    Il se trouve que dans le cas des vecteurs, les itérateurs sont en général par des pointeurs, ce qui n'est pas une obligation. Ce qui explique que ton premier appel soit accepté par le compilateur. Les paramêtres tab, et (tab + 5) sont implicitement convertis en itérateur sur un vecteur d'entier. Et le constructeur prenant en paramètre un intervalle défini par 2 itérateurs est correctement appelé.

    En revanche, les itérateurs sur un deque ne sont jamais directement implanté par un simple pointeur, ce qui fait que l'appel échoue.

    En conclusion, si le premier appel compile, c'est uniquement *par hasard*.

    Pour initialiser un vecteur à partir d'un tableau, on s'y prend généralement de la manière suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main()
    {
      int tab={11,22,33,44,55};
      vector<int> conteneur;
      conteneur.resize(5);
      memcpy(&conteneur[0], tab, 5*sizeof(int));
    }
    Pour initialiser un deque a partir d'un tableau, soit on insere les éléments un à un. Soit on charge le tableau dans un vecteur et on utilise l'algorithme copy() (spécial fainéant).

  4. #4
    jmv
    jmv est déconnecté
    Membre confirmé Avatar de jmv
    Profil pro
    Enseignant
    Inscrit en
    Mai 2004
    Messages
    395
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2004
    Messages : 395
    Points : 603
    Points
    603
    Par défaut
    Citation Envoyé par VoidSeer
    un itérateur n'est pas un pointeur.
    Non mais un pointeur est un itérateur (ou peut s'utiliser comme tel)
    Chez moi le code suivant passe trés bien avec DEV-C++
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main()
    {
        int tab[] = { 1,2,3,4,5,6 };
        vector<int> ve(tab, tab+6);
        deque<int> de(tab, tab+6);
        list<int> li(tab, tab+6);
    }

    Citation Envoyé par VoidSeer
    En conclusion, si le premier appel compile, c'est uniquement *par hasard*.
    Non, c'est dans le cahier des charges de la STL, un pointeur doit pouvoir être utilisé comme itérateur.



    Citation Envoyé par VoidSeer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main()
    {
      int tab={11,22,33,44,55};
      vector<int> conteneur;
      conteneur.resize(5);
      memcpy(&conteneur[0], tab, 5*sizeof(int));
    }
    ça c'est de la bidouille !!!
    [EDIT]
    c'est pas de la bidouille, ça marche, voir post suivant
    [/EDIT]

    Excuse moi VoidSeer mais tu ne doit pas être très bien réveillé

  5. #5
    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 : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Je confirme... Le constructeur prenant en paramètre 2 itérateurs est bien là (sauf sous VC6), et au pire il y a toujours assign ou copy avant d'en arriver là

  6. #6
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Un pointeur est même un itérateur à accès direct ("random access iterator"), et par conséquent un "input itérator". Il est donc parfaitement valide en paramètre de std::deque.
    L'erreur est ici dans une vieille STL qui allait avec un vieux compilo.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Citation Envoyé par jmv
    Citation Envoyé par VoidSeer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main()
    {
      int tab={11,22,33,44,55};
      vector<int> conteneur;
      conteneur.resize(5);
      memcpy(&conteneur[0], tab, 5*sizeof(int));
    }
    ça c'est de la bidouille !!!
    Nan, c'est directement l'application de l'item 16 de "Effective STL", S. Meyer - Addison-Wesley.

    Quant au reste, mea culpa, j'ignorais qu'un pointeur simple était un itérateur valide sur un deque.
    Au deuxième coup d'oeil, ça paraît logique, vu l'interface requise pour un random access iterator. Effectivement, je ne devais pas être bien frais

  8. #8
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 751
    Points : 10 670
    Points
    10 670
    Billets dans le blog
    3
    Par défaut
    Y compris le memcpy ?
    On préfèrera std::copy() en C++.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    std::copy( conteneur.begin(), conteneur.end(), tab );

  9. #9
    jmv
    jmv est déconnecté
    Membre confirmé Avatar de jmv
    Profil pro
    Enseignant
    Inscrit en
    Mai 2004
    Messages
    395
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2004
    Messages : 395
    Points : 603
    Points
    603
    Par défaut
    Citation Envoyé par VoidSeer
    Citation Envoyé par jmv
    Citation Envoyé par VoidSeer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main()
    {
      int tab={11,22,33,44,55};
      vector<int> conteneur;
      conteneur.resize(5);
      memcpy(&conteneur[0], tab, 5*sizeof(int));
    }
    ça c'est de la bidouille !!!
    Nan, c'est directement l'application de l'item 16 de "Effective STL", S. Meyer - Addison-Wesley.
    le pb est que tu suppose que les éléments d'un vecteur sont contigus, c'est vrai dans 99,99% des implémentations de la STL (peut-être même 100%) mais ça n'est pas garanti par la norme.

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Le memcpy est parfaitement licite, et pas bidouille car le standard impose que les vecteurs stockent leurs éléments de la même manière qu'un tableau.

    EDIT: @jmv, c'est garanti par la norme

  11. #11
    jmv
    jmv est déconnecté
    Membre confirmé Avatar de jmv
    Profil pro
    Enseignant
    Inscrit en
    Mai 2004
    Messages
    395
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2004
    Messages : 395
    Points : 603
    Points
    603
    Par défaut
    Citation Envoyé par VoidSeer
    EDIT: @jmv, c'est garanti par la norme
    ha... tu as peut-être raison mais alors Delannoy et Stroustrup se sont trompé dans leur bouquin.

    Je croyais que seul l'accés aléatoire en O(1) était garanti.

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Non, le stockage des données mémoire de manière contigüe est imposé. Bien sûr, ça n'a que peu d'importance sur un tableau à 5 éléments, mais le fait d'utiliser un 'memcpy' à la place d'un algorithme STL m'a fait gagner pas mal de temps dans des parties de code critiques.

  13. #13
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    - La contiguité des éléments d'un vecteur est garantie par la norme.
    Que le Delannoy se trompe ne m'étonne pas plus que ça (il fait parti de ces bouquins recommandés qui n'ont pas très bonne réputation chez les initiés), qu'il y ait une erreur dans le bouquin de Stroustrup c'est autre chose. Quelle version ? La dernière traduction révisée (techniquement) par Michel Michaud ? Une autre ? Que disent les errata associés à ta version ?

    - Aurélien, tu a été étourdi , le memcpy (&vecteur[0], tab, size_tab) se traduit en std::copy(tab, tab+size_tab, &vecteur[0]);

    - Le surcout de std::copy par rapport à memcpy est au pire une légende, et normalement un problème résolu avec les implémentations d'aujourd'hui de la STL avec les compilos qui savent inliner. Perso je garde memcpy que lorsque j'ai des tailles (et non des plages) et des données POD (très important le POD, memcpy n'est pas utilisable sinon). Typiquement en sortie de socket.

    Et perso, j'aime assez écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    std::copy(ll::begin(tab), ll::end(tab), std::back_inserter(vecteur));
    // voire directement
    ll::copy(tab, std::back_inserter(vecteur));
    Les facilités qui permettent d'écrire ce genre de choses sont assez courantes et vite intégrées dans un projet.


    Sinon, il y a un projet de boost qui permet d'initialiser des containers de façon "simple" sans passer par la case tableau statique.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  14. #14
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 751
    Points : 10 670
    Points
    10 670
    Billets dans le blog
    3
    Par défaut
    Pour std::copy, apparement je me suis mal exprimé. J'ai pas voulu dire que le memcpy était faux, juste que c'est plus C que C++, et que std::copy me parraît plus naturel avec un vector ou autre conteneur STL.
    C'est quoi POD ?

  15. #15
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut


    Sinon POD, c'est "plain old data". Cela correspond aux types composés à partir des types primitifs. En sont exclues de sûr les classes. J'ai un doute quant à savoir si on peut y mettre des fonctions membres simples.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  16. #16
    jmv
    jmv est déconnecté
    Membre confirmé Avatar de jmv
    Profil pro
    Enseignant
    Inscrit en
    Mai 2004
    Messages
    395
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2004
    Messages : 395
    Points : 603
    Points
    603
    Par défaut
    Dans "le langage C++" de Stoustrup, édition spéciale revue et corrigée (c)2003, page 518 chapitre 17.1.3
    La représentation:
    Le standard n'impose pas de représentation particulière pour chaque conteneur. Il en spécifie simplement les interfaces et quelques conditions de complexité...
    Pour un vector, la structure de donnée sera très certainement un tableau.
    pour moi, "très certainement" ne veut pas dire "obligatoirement". Donc méfiance avec memcpy(). Par contre std::copy() fonctionne même si les éléments ne sont pas contigus à condition d'utiliser des vrais itérateurs (pas des pointeurs, qui sont des itérateurs de tableau).

    Bon, maintenant, c'est vrai que "standard" != "norme". Où peut-on trouver cette norme ?

  17. #17
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    La norme ISOIEC14882-1998 s'achète -- il doit y avoir des liens dans la FAQ, au pire ça y est dans la FAQ C++ lite.

    Mais ce point particulier se trouvera dans la révision (acceptée, il va de soi) de celle ci dont le PDF est disponible librement sur le site de Bjarne Stroustrup.
    Citation Envoyé par Le commité, dans la révision de la norme, p167 §23.2.4. 1,
    [...]The elements of a vector are stored contiguously, meaning that if v is a vector<T,Allocator> where T is some type other than bool, then it obeys the identity: &v[n] == &v[0] + n for all 0 <= n < v.size().
    Les implémenteurs sont libres de mettre en oeuvre les vecteurs comme ils le désirent, mais il est clair que cette contrainte forte rend impossible l'utilisation d'autre chose que d'un tableau pour stocker les éléments en interne.

    (standard <~> norme ; la norme est le papier qui définit le C++ standard, je crois)

    En conclusion, on peut utiliser memcpy comme std::copy sur les vecteurs -- au détail que memcpy n'est utilisable que pour les types POD, qu'il marche directement pour extraire des données des vecteurs, et qu'il nécessite un redimensionnement (resize != reserve) du vecteur avant écriture -- std::copy permet d'utiliser les back_inserter.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  18. #18
    jmv
    jmv est déconnecté
    Membre confirmé Avatar de jmv
    Profil pro
    Enseignant
    Inscrit en
    Mai 2004
    Messages
    395
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2004
    Messages : 395
    Points : 603
    Points
    603
    Par défaut
    merci pour ces précisions
    et mille excuses à VoidSeer: son code fonctionne et n'a rien de bidouille puisqu'il respecte la norme.

  19. #19
    Membre régulier Avatar de gelam
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2003
    Messages : 69
    Points : 74
    Points
    74
    Par défaut
    Un grand merci à tous. Je ne pensais pas lancer un discussion aussi passionée.
    Concernant la discussion itérateur-pointeur : Mon point de vue est qu'un pointeur n'est pas un itérateur et un itérateur n'est pas un pointeur mais qu'ils partagent la même interface si le conteur fournit un random iterator.
    Tous deux fournissent les opérateurs suivants :
    r++ r--
    r+=n r-=n
    s=r+n
    s=r-n
    n=r-s
    r<s, r<=s, r>s, r>=s
    où r et s sont des itérateurs et n un entier
    ( tout ceci en plus de r==s, r!=s, *r )

    bon WE à tous
    Avez-vous remarqué les progrès que fait l'ignorance?
    [Tristan Bernard ]

  20. #20
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Un pointeur est une des formes d'itérateur. SGI le dit, et je pense que le commité de standardisation a gardé ce fait.
    Et tous les itérateurs ne sont pas des itérateurs à accès direct (random access iterators) dont tu as donné une partie de la sémantique (http://www.sgi.com/tech/stl/RandomAccessIterator.html)
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 15/05/2010, 11h57
  2. problème avec la STL sous solaris
    Par sofiane80 dans le forum SL & STL
    Réponses: 12
    Dernier message: 01/12/2009, 14h26
  3. Problème dans requête avec count()
    Par BadFox dans le forum Requêtes
    Réponses: 3
    Dernier message: 08/07/2003, 18h02
  4. Problèmes de versions avec Xalan, Xerces et Java
    Par honeyz dans le forum XML/XSL et SOAP
    Réponses: 4
    Dernier message: 05/06/2003, 10h18
  5. [Kylix] [BCB] pb avec la STL
    Par pykoon dans le forum EDI
    Réponses: 1
    Dernier message: 29/12/2002, 12h56

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