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 :

vector::reserve(), un hack dangereux ?


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 293
    Billets dans le blog
    2
    Par défaut vector::reserve(), un hack dangereux ?
    Salut,

    il y a un truc qui me turlupine depuis quelques jours.

    Observez donc ce rapport quick bench:
    http://quick-bench.com/IHmmxt68FTep6DqRaD3yxRTU7g0

    Je compare trois méthodes de construction et de remplissage d'un std::vector :
    Première méthode (reserve) : Je construis un vector vide, puis je réserve la taille dont j'ai besoin, puis je le remplis
    Deuxième méthode (construct) : Je construis un vector directement alloué, puis je le remplis
    Troisième méthode (cstyle): J'alloue un tableau "c-style", puis je le remplis

    On voit que le reserve est aussi rapide que le cstyle. Ce qui est normal, puisque le reserve fait un malloc.
    Mais on voit aussi que de construire directement le vector est sensiblement plus lent. Ce qui, il me semble, est dû au fait que le constructeur de vector appelle le constructeur par défaut de chaque objet qu'il contient.

    La question que je me pose, dans cette histoire, c'est si la première méthode (reserve) n'est pas dangereuse ?
    Car finalement, ce qu'on fait dans ce cas, c'est juste allouer de la mémoire, mais on a aucun filet. Quels sont les risques qu'impliquent cette façon de faire ?

  2. #2
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Si tu utilises correctement l'interface de vector il n'y a aucun risque : la mémoire allouée via reserve n'est pas (facilement) accessible, la taille réelle et le nombre d'éléments présents est gérée à part.
    Oui la construction avec le nombre d'éléments fera appel au constructeur de copie de l'élément que tu passes en paramètres, qui est construit par défaut si tu n'en passes aucun.
    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
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 293
    Billets dans le blog
    2
    Par défaut
    J'ai trouvé un cas qui peut être gênant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    std::vector<int> v;
    v.reserve(100);
    for(int i = 0; i<100 ; ++i)
    	v[i] = i;
     
    cout << v.at(10) << endl;
    Le v.at(10) lève une exception.
    Ça peut être embêtant je ne me rend pas compte. Je ne me souviens pas n'avoir jamais vu vector::at() utilisé en 15 ans de carrière.

  4. #4
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Sauf que tu présentes une mauvaise utilisation.
    reserve alloue de la mémoire mais pas des objets, tu utilises des int donc ça tombe en marche mais ce n'est pas valide.
    at fait un check de la taille et lève une exception, [] n'en fait pas mais son utilisation ici est incorrecte.
    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.

  5. #5
    Membre émérite

    Profil pro
    Inscrit en
    Décembre 2013
    Messages
    403
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 403
    Par défaut
    Il faut prendre l'habitude de checks les préconditions, sinon on peut faire trop facilement ce genre d'erreur. Avec un assert, tu aurais eu l'info que le code n'est pas valide.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    assert(i < size(v));
    v[i] = Dum(i, i+1);
    Avec un push_back, les perfs sont très mauvaises, mais avec un emplace_back, les perfs sont proches de celle de malloc. Cela permet d'éviter les initialisations par défaut des éléments du vector, ce qui prend pas mal de temps. Mais il reste quand meme la mise a jour de la taille du vector.

    Dans tous les cas, ca ne sera jamais aussi rapide qu'un simple malloc. A commencer par le fait qu'ils ne font pas la meme chose : vector est conçu pour changer de taille plusieurs fois, alors que malloc n'a pas a gerer les resize. L'équivalent de malloc serait les VLA ou un unique_ptr<Dum[]> ou ecrire un fixed_vector ou un uninitialized memory.

    Nom : Screen Shot 2019-09-18 at 23.26.11.png
Affichages : 220
Taille : 67,7 Ko

  6. #6
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 293
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par mintho carmo Voir le message
    Il faut prendre l'habitude de checks les préconditions, sinon on peut faire trop facilement ce genre d'erreur. Avec un assert, tu aurais eu l'info que le code n'est pas valide.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    assert(i < size(v));
    v[i] = Dum(i, i+1);
    Effectivement, là tu montres bien ce qui ne va pas dans mon code. Quand on reserve(), la size du vector de change pas, uniquement sa capacity.
    C'est donc dangereux de faire juste un reserve() sans construire réellement les éléments du vector.

    Citation Envoyé par mintho carmo Voir le message
    Avec un push_back, les perfs sont très mauvaises, mais avec un emplace_back, les perfs sont proches de celle de malloc. Cela permet d'éviter les initialisations par défaut des éléments du vector, ce qui prend pas mal de temps. Mais il reste quand meme la mise a jour de la taille du vector.
    Je suis curieux de voir le code que tu as utilisé pour ton test. Parce que ces derniers temps, j'ai eu des mauvaises surprises en profilant du code utilisant du emplace_back(), et je me pose actuellement pas mal de questions.

    Citation Envoyé par mintho carmo Voir le message
    Dans tous les cas, ca ne sera jamais aussi rapide qu'un simple malloc.
    Effectivement, et c'est toujours bien de le rappeler.
    Les jeunes arrivent la tête pleine de POO, et refusent de croire des choses aussi évidentes que celles-là. Comme le prix de l'héritage (vtable), ou des architectures trop complexes quand on peut faire simple. Mais je m'égare...

  7. #7
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Citation Envoyé par r0d Voir le message
    J'ai trouvé un cas qui peut être gênant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    std::vector<int> v;
    v.reserve(100);
    for(int i = 0; i<100 ; ++i)
    	v[i] = i;
     
    cout << v.at(10) << endl;
    Le v.at(10) lève une exception.
    Ça peut être embêtant je ne me rend pas compte. Je ne me souviens pas n'avoir jamais vu vector::at() utilisé en 15 ans de carrière.
    Ecrire dans un vector<> qui est vide est en effet plutôt "osé".
    Peux-être as-tu confondu la ligne 2 avec v.resize(100); qui lui aurait préparé un vector<> de 100 élements. Et alors les v[i] deviennent possibles et évidement le at() aussi.

  8. #8
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 293
    Billets dans le blog
    2
    Par défaut
    Non justement, j'essayais d'évaluer les risques de cette pratique. C'est la raison pour laquelle je parle de "hack" dans le titre.

  9. #9
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Mais c'est pas une pratique, c'est juste du code de quelqu'un qui n'a rien compris à l'interface de vector...
    Tu peux aussi écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::unique_ptr<int> myint;
    *myint = 5;
    Et tu vas avoir des problèmes, pour autant c'est pas la faute à unique_ptr, c'est le programmeur qui est un abruti.
    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.

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

Discussions similaires

  1. reserve d'un std::vector impossible
    Par Sahengette dans le forum Langage
    Réponses: 15
    Dernier message: 08/03/2012, 20h02
  2. vector reserve & accession
    Par Julgood dans le forum SL & STL
    Réponses: 3
    Dernier message: 19/03/2009, 01h19
  3. equivalent Vector du jsp
    Par Djib dans le forum ASP
    Réponses: 4
    Dernier message: 05/12/2003, 08h07
  4. "vector" provoque "syntax error", malgré
    Par seenkay dans le forum Autres éditeurs
    Réponses: 5
    Dernier message: 24/08/2003, 03h21
  5. Réponses: 2
    Dernier message: 11/07/2003, 18h24

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