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. #21
    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
    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.
    Je ne vois vraiment pas ce que tu veux dire par là... Un vector n'a aucunement besoin d'un constructeur par défaut (j'ai juste eu le soucis avec un vieux compilo qui en réclamait un, mais il était en tort). Il a besoin d'allouer de la mémoire non initialisée, avant d'y copier/déplacer des objets, mais ça n'a rien à voir avec la création d'objets vides.
    Citation Envoyé par white_tentacle Voir le message

    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.
    Si les perfs comptent vraiment, la list, qui n'est pas cache-friendly n'est peut-être pas une super idée. En plus, ça prend pas mal de mémoire. Le deque a aussi une certaine stabilité, mais dès que les objets font quelques octets, ils se transforment généralement en tableau de pointeurs, et donc fragmentent aussi la mémoire.
    Citation Envoyé par white_tentacle Voir le message
    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.
    boost::multi_index, ou son wrapper simplifié boost::bimap. Mais je doute que ça marche bien sur le sous ensemble du C++ qu'a l'air d'être Arduino...
    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.

  2. #22
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Citation Envoyé par fma38 Voir le message
    Non, pas de chance, pas de C++1
    C'est faux.

    Tu compiles pour arduino avec avr-g++, qui juste un compilateur g++ classique mais qui produit du code pour ... ARM

    Il y a cependant quelques restrictions : IIRC pas de RTTI ni d'exceptions

    Il suffit d'activer le flag pour utiliser C++11 (sans la STL) sans soucis.
    Pour la STL, ya des portages, mais plus des portages de la STL de C++03.

    Apres, ya des soucis lies au fait qu'on soit sur un microcontroleur.
    On est vite limité en RAM, avr-g++ place les vtable en Flash ET en RAM,...

    Pour info, jai passé un an a code sur une Arduino mega avec Emacs, Makefile & C++11 et j'ai pu utiliser des varuadic templates , du tag-dispatch et des std::vector

    Sinon tu peux détailler ?

    • ta carte: Uno/Mega/Due/...
    • Ton problème exact avec un peu de code
    • Tes contraintes: performance ou occupation de ram ?

    Car un vecteur de unique_ptr que tu tries au besoin, ca peut s'envisager.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  3. #23
    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ïe, pas taper !! Chuis développeur python, moi

    Je vais voir pour activer ces fameux flags...

  4. #24
    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 Davidbrcz Voir le message
    Sinon tu peux détailler ?

    • ta carte: Uno/Mega/Due/...
    • Ton problème exact avec un peu de code
    • Tes contraintes: performance ou occupation de ram ?

    Car un vecteur de unique_ptr que tu tries au besoin, ca peut s'envisager.
    Le projet est celui-ci :

    https://www.logre.eu/wiki/JIXClock

    Je suis en train de refaire le firmware du copain mais plus orienté objet. La cible est un Nano.

    Côté perfs, je n'ai pas trop de souci : il s'agit de rafraichir les leds pour que visuellement ça rende bien ; 20ms est largement suffisant pour faire déjà des effets de transitions de couleurs sympas.

    Par contre, côté mémoire, c'est vite plein !

    En gros, j'ai un objet DisplayData, qui contient des DigitData, lesquels contiennent des LedData. L'objet DisplayData est mis à jour par le modèle, et utilisé par la vue pour rafraichir l'horloge (ou sortir sur la console quand je n'ai pas le hard complet sous la main, mais juste un petit Arduino).

    Ce que je veux, c'est, dans DisplayData et DigitData, avoir des itérateurs qui me retournent des références sur les LedData, dans un ordre spécifique. Histoire de pouvoir facilement récupérer les LedData par colonne, par ligne, ou tout autre tri qui passera par la tête d'un designer fou

    L'idée est d'avoir une structure facile à utiliser pour ajouter des modes de couleurs, de patterns, etc.

    Je vais pusher le code sur github d'ici peu, histoire que vous puissiez voir le code... À condition de me promettre de ne pas rire !

  5. #25
    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

  6. #26
    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
    En gros, tu remplaces
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    T::T(int param1, std::string const& param2, int* param3)
    par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    T::T() :
      membre1(0),
      membre2(),
      membre3(NULL)
    {
    }
    void T::init(int param1, std::string const& param2, int* param3)
    {
      membre1 = param1;
      …
    }
    et ensuite, tu fais au niveau de ton vecteur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    v.resize(v.size() +1);
    v.back().init(param1, param2, param3);
    Ça t’évite de construire un objet localement.

    Si tu connais à l’avance la taille de ton vecteur (ou un majorant raisonnable de celle-ci), tu as clairement intérêt à l’allouer au départ avec v.reserve() --> ton vecteur fera alors normalement exactement la bonne taille, sans « gâchis » de mémoire, alors que par allocations successives, il y a de bonnes chances qu’il alloue trop.

  7. #27
    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
    Citation Envoyé par JolyLoic Voir le message
    Je ne vois vraiment pas ce que tu veux dire par là... Un vector n'a aucunement besoin d'un constructeur par défaut (j'ai juste eu le soucis avec un vieux compilo qui en réclamait un, mais il était en tort).
    Effectivement, c’est nécessaire seulement si on utilise resize(). Merci pour la correction

  8. #28
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par fma38 Voir le message
    Pigé.

    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).
    Si tu n'as vraiment que 2ko de ram tu peux probablement laisser tomber toutes les réponses qu'on t'as faite dans ce thread... Avec des contraintes aussi fortes, toute solution générale qu'on pourra te donner sera très probablement inappropriée.

    Déjà rien que le fait d'utiliser std::vector me semble très surprenant. std::vector alloue avec new dans le tas, et possède son propre pattern d'allocation (il alloue souvent plus que nécessaire pour éviter d'avoir à réallouer lors d'ajout d'élément), donc est-ce que c'est vraiment sage d'utiliser un vector alors que la mémoire est aussi ric-rac ?

    En plus tu dis qu'allouer un peu trop fait carrément crasher la machine ! J'ai tendance à penser qu'il faudrait que tu puisses gérer précisément le budget mémoire, par exemple en préallouant un tableau statique de taille fixe égale au nombre maximum d'objet autorisé et qui contiendra tes objets.

    D'ailleurs avec aussi peu de mémoire ça veut dire que ton tableau ne contiendra que très peu d'objet au final, en fait vu qu'ils font chacun 20 octets et que tu n'as que 2k ça veut dire que ton nombre total d'objet ne dépassera jamais (2k)/20 = 102. Donc pour le tri le moins coûteux en mémoire serait probablement d'avoir un deuxième tableau de char (char == codé sur un seul octet) de la même taille que ton tableau principal. Chaque case contient alors un numéro (entre 1 et 255 vu que c'est un char) qui est en fait un index vers ton tableau principal. Avec cette technique cela veut dire qu'avec 102 octets maximum tu peux encoder un tri de ton tableau principal.

  9. #29
    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
    Yep, le tableau de uint8_t (qui est un bête alias sur unsigned char), c'est ce que j'ai finalement fait pour le moment, en attendant de trouver mieux.

    J'aurais bien utilisé array, mais pas dispo (faut faire tout un tas de galipettes pour utiliser un compilo plus récent dans l'IDE Arduino, et comme je veux que ça se compile facilement par un non spécialiste...).

    Par contre, j'alloue mes vector avec reserve(), comme indiqué. Et je monitor la mémoire lors des devs.

  10. #30
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    vector::reserve() c'est typiquement le genre de fonction que le standard autorise à faire allouer plus que la taille passée en paramètre, mais heureusement il me semble qu'en pratique toutes les implémentations connues alloue pile la taille demandée.

    Ça m'épate toujours un peu qu'avec à peine 2ko de ram les std::vector soient disponibles (et donc les malloc/new le soient aussi)

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