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

Langage C++ Discussion :

std::vector et références


Sujet :

Langage C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    117
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 117
    Points : 33
    Points
    33
    Par défaut std::vector et références
    Bonjour,

    J'essaye d'optimiser un programme C++ embarqué (Arduino).

    Dans ce programme, je crée des objets que je range dans un vector. Je voudrais pouvoir les récupérer dans un autre ordre. Pour éviter de créer des copies, j'essaye d'utiliser les références, mais ça ne passe pas à la compile : j'ai l'impression qu'il est impossible de déclarer un vector de références... Me goure-je ?

    Merci de vos lumières.

    PS : je voudrais éviter les pointeurs autant que possible...

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Un tableau de références est impossible
    Pour éviter les copies, de simples objets suffisent
    Ce n'est pas les objets qui passent en références, mais le tableau lui-même
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    117
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 117
    Points : 33
    Points
    33
    Par défaut
    Pas sûr de comprendre... Peux-tu me dire comment tu fais sur un petit exemple ?

  4. #4
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Si tu es en C++11, remplis ton vecteur avec la méthode emplace_back(), et quand tu veux exploiter les valeurs, extrait les vers des références constantes.

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    117
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 117
    Points : 33
    Points
    33
    Par défaut
    Non, pas de chance, pas de C++1

    La question est : si je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    vect2.push_back(vect1[i])
    est-ce que je crée une copie de l'objet vect1[i] que j'ajoute ensuite à vect2, ou est-ce que c'est le même objet qui est inséré ?

  6. #6
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    push_back crée une copie (ou un déplacement en C++11 si l'objet est temporaire).
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par fma38 Voir le message
    Non, pas de chance, pas de C++1

    La question est : si je fais :

    vect2.push_back(vect1[i])

    est-ce que je crée une copie de l'objet vect1[i] que j'ajoute ensuite à vect2, ou est-ce que c'est le même objet qui est inséré ?
    Non, ce sera d'office une copie.

    l'opérateur [] renvoie une référence (éventuellement constante) sur l'objet qui est situé à l'indice indiqué entre les crochets, et une référence ne peut -- comme tu l'as si bien fait remarquer -- pas prendre place dans une collection.

    La raison est simple : une référence n'est qu'un alias de l'objet référencé. Elle n'a donc pas d'existence réelle bien à elle (elle n'existe qu'au travers de l'objet référencé).

    il y a donc, forcément, copie lorsque tu utilises le résultat de l'opérateur [] pour remplir un autre tableau.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  8. #8
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Si c’est pour les récupérer dans un autre ordre, une solution est d’avoir un vecteur de pointeurs qui sert d’index.

    Attention toutefois à ce que ton vecteur initial ne change pas : sinon, ton index est invalidé et tu dois le reconstruire.

  9. #9
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    117
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 117
    Points : 33
    Points
    33
    Par défaut
    Ok, merci pour vos réponses.

    En fait, je crois que je vais même aller plus loin, et faire ça plus propre, avec un itérateur spécialisé. C'est possible, non ? Il en faudrait plusieurs, en fait (différents ordres)...

  10. #10
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Si tu voulais éviter la complexité des pointeurs, ne va pas te lancer dans la complexité d'implémentation d'un itérateur...

  11. #11
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    117
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 117
    Points : 33
    Points
    33
    Par défaut
    Euh, ce n'est pas la complexité qui me fait tenir loin des pointeurs ; c'est parce que c'est casse-gueule au possible.

    Implémenter un itérateur, c'est quand même plus propre. Au moins, j'apprendrai quelque chose. Alors qu'avec les pointeurs, à part m'arracher les cheveux à trouver ce qui merde...

  12. #12
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Personne n'a parlé de std::reference_wrapper (C++11) ou boost::reference_wrapper ?

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    struct data {
    	int i;
    	data(int i): i(i) { }
    	data(const data& d) {
    		assert(0);
    	}
    };
     
    int main() {
     
    	typedef std::vector<std::reference_wrapper<data>> vec_type;
     
    	vec_type vec, vec2; 
     
    	data d(0);
    	vec.push_back(d);
    	vec2.push_back(vec[0]);
     
    	d.i = 1;
    	assert(d.i == 1);
    	assert(d.i == vec[0].get().i);
    	assert(d.i == vec2[0].get().i);
     
    	return 0;
    }

  13. #13
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    117
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 117
    Points : 33
    Points
    33
    Par défaut
    Ça avait l'air bien, mais ce n'est malheureusement pas dispo dans l'implémentation de la libstdc++ que j'utilise sur Arduino...

    Merci quand même !

    Bon, côté iterateurs, c'est vrai que c'est un peu pédestre ! J'ai bêtement imaginé que ça pouvait se faire aussi simplement qu'en python

    Tant pis, je vais y aller à coup de pointeurs. Tout en finesse !

  14. #14
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Un moyen simple d'éviter une copie c'est de commencer par le push_back (ou insert) puis de l'initialiser (les initialiser) avec back ou []
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  15. #15
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    117
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 117
    Points : 33
    Points
    33
    Par défaut
    Initialiser l'objet qu'on vient de mettre dans le vector ? Mais comment le créer sans l'initialiser ? Un truc m'échappe...

  16. #16
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Un vector a forcément besoin de créer des objets (avec le constructeur par défaut) avant de pouvoir y stocker de véritables objets.

    En fait, la bonne question, c’est :
    - la copie de tes objets est-elle réellement coûteuse (s’ils font moins de 20 octets, ça se discute très sérieusement)
    - es-tu bien sûr que c’est de vector que vient ton éventuel problème de perf.

    En tout cas, je maintiens ce que j’ai dit initialement : s’il s’agit juste de présenter une collection de gros objets sous différents ordres, j’adopterai la structure suivante :
    - un std::list<T> container, qui stocke les objets. Comme tu vas devoir reconstruire tes index à chaque modification, la std::list est probablement plus adaptée que le vector. Si ta collection ne change jamais, ça se discute plus.
    - pour chaque « ordre », un std::vector<std::list<T>::iterator> qui donne accès aux éléments de ta liste dans l’ordre voulu.

    Bien sûr, pour les classes clientes, pas d’accès direct à la liste initiale afin de s’assurer que les index restent en phase à chaque suppression / insertion.

    L’autre solution, si jamais tu peux l’utiliser, est qu’il y a une multi_ordered_map (ou quelque chose de similaire) dans boost, si mes souvenirs sont bons.

  17. #17
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    117
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 117
    Points : 33
    Points
    33
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Un vector a forcément besoin de créer des objets (avec le constructeur par défaut) avant de pouvoir y stocker de véritables objets.
    Pigé.

    En fait, la bonne question, c’est :
    - la copie de tes objets est-elle réellement coûteuse (s’ils font moins de 20 octets, ça se discute très sérieusement)
    - es-tu bien sûr que c’est de vector que vient ton éventuel problème de perf.
    Je suis en embarqué, avec 2ko de RAM ! 20 octets par objet, ça rempli vite le bastringue. Et oui, mon souci vient bien du fait que si je duplique le contenu du vector, je crash le bignou, faut de RAM (avec un quick hack pointeurs, il me reste 500 octet de libre).

    En tout cas, je maintiens ce que j’ai dit initialement : s’il s’agit juste de présenter une collection de gros objets sous différents ordres, j’adopterai la structure suivante :
    - un std::list<T> container, qui stocke les objets. Comme tu vas devoir reconstruire tes index à chaque modification, la std::list est probablement plus adaptée que le vector. Si ta collection ne change jamais, ça se discute plus.
    - pour chaque « ordre », un std::vector<std::list<T>::iterator> qui donne accès aux éléments de ta liste dans l’ordre voulu.
    Ma collection ne change pas, donc le vector est moins gourmand, non ?

    Je vais plancher sur cette solution, même si je ne vois pas encore bien comment implémenter ça... Comment utilises-tu un vector d'iterator ?

    Bien sûr, pour les classes clientes, pas d’accès direct à la liste initiale afin de s’assurer que les index restent en phase à chaque suppression / insertion.
    Oeuf corse...

    L’autre solution, si jamais tu peux l’utiliser, est qu’il y a une multi_ordered_map (ou quelque chose de similaire) dans boost, si mes souvenirs sont bons.
    Si le code n'est pas trop gros, je peux essayer d'intégrer cette partie à mon code (paraît que boost est très modulaire), mais je n'ai pas boost sur l'Arduino

    Merci !

  18. #18
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par fma38 Voir le message
    Ça avait l'air bien, mais ce n'est malheureusement pas dispo dans l'implémentation de la libstdc++ que j'utilise sur Arduino...
    Dispo dans TR1, ou au pire dans Boost.

  19. #19
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par fma38 Voir le message
    Initialiser l'objet qu'on vient de mettre dans le vector ? Mais comment le créer sans l'initialiser ? Un truc m'échappe...
    Tout simplement en insérant des objets par défaut, avec le constructeur par défaut avant de les initialiser pour de bon, et non d'y copier des objets déjà initialisés
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  20. #20
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    117
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 117
    Points : 33
    Points
    33
    Par défaut
    Ok, mais j'aurai bien 2 objets différents, un dans chaque vector, non ? Au final, ça prendra la même place en mémoire ?

    Je veux bien un bout de code d'exemple, car là, je suis largué

Discussions similaires

  1. Réponses: 6
    Dernier message: 06/06/2013, 11h23
  2. Retourner une référence sur un std::vector
    Par Rodrigue dans le forum C++
    Réponses: 12
    Dernier message: 13/10/2007, 16h30
  3. char[50] et std::vector<>
    Par tut dans le forum SL & STL
    Réponses: 9
    Dernier message: 12/10/2004, 13h26
  4. Réponses: 8
    Dernier message: 26/08/2004, 18h59
  5. Sauvegarde std::vector dans un .ini
    Par mick74 dans le forum MFC
    Réponses: 2
    Dernier message: 12/05/2004, 13h30

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