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 bonne pratique


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné

    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2009
    Messages
    377
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Novembre 2009
    Messages : 377
    Par défaut std::vector bonne pratique
    Bonjour,

    j'aimerai savoir quelle est la meilleur pratique pour l'utilisation d'un std::vector.

    Sachant que celui-ci fait une copie lors d'un push_back, vaut-il mieux insérer des pointeurs (intelligent ou non) ou insérer l'objet lui-même.

    Quel est la meilleurs version :

    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
     
    #include <vector>
    #include <stdio.h>
    #include <iostream>
     
    int main()
    {
    	std::vector<std::string*> vec_test;
     
    	std::string* s1 = new std::string("Blabla");
     
    	vec_test.push_back(s1);
     
    	for (std::vector<std::string*>::iterator it = vec_test.begin(); it!=vec_test.end(); ++it)
    	{
    		delete *it;
    	}
     
    	return 1;
    }
    ou la version "simple" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <vector>
    #include <stdio.h>
    #include <iostream>
     
    int main()
    {
    	std::vector<std::string> vec_test;
     
    	std::string s1 = "Blabla";
     
    	vec_test.push_back(s1);
     
    	return 1;
    }

    Je trouve la première plus efficace (pas de copie des données), mais il y a la gestion des pointeurs.

  2. #2
    Membre émérite

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

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Par défaut
    Si ton compilateur gère le C++11 (c'est très probable) il suffit d'utiliser la sémantique de mouvement, de cette manière :

    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
     
    std::vector<std::string> vec_test;
     
    // #1
    std::string s1 = "Blabla";
    vec_test.emplace_back(std::move(s1)); // [edit] correction suite à la remarque de gbdivers
    //ou vec_test.emplace_back("Blabla")
    assert ( s1.empty() );
     
    // #2
    vec_test.push_back("Blabla")
    //ou vec_test.push_back(std::string("Blabla"))
     
    // #3
    std::string s2 = "Blabla";
    vec_test.push_back(std::move(s2));
    assert ( s2.empty() );
    Ces trois méthodes déplacent la chaine à la fin du vecteur d'une manière optimale, sans avoir à s’embarrasser de new/delete.

  3. #3
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Petite correction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // #1
    std::string s1 = "Blabla";
    vec_test.emplace_back(s1);
    assert ( s1.empty() );
    emplace_back permet de créer un élément directement dans le conteneur sans faire de copie. Il prend en paramètre les arguments que l'on aurait utilisé pour créer la chaine. Il ne s'agit pas de move sémantique (cela utilise les variadic template) et dans ton code #1, tu as bien une copie. Pour éviter la copie, il faut écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // #1
    vec_test.emplace_back("Blabla");
    La confusion vient peut être du fait que le prototype de emplace_back est template< class... Args > void emplace_back( Args&&... args ); ce qui fait penser à la move semantic, mais il s'agit de perfect forwarding ici


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    // #2
    vec_test.push_back("Blabla")
    //ou vec_test.push_back(std::string("Blabla"))
     
    // #3
    std::string s2 = "Blabla";
    vec_test.push_back(std::move(s2));
    assert ( s2.empty() );
    Là ok, c'est bien de la move semantic (appelle de la version push_back(T&&) au lieu de push_back(const&)). La move semantic est obtenu en utilisant un temporaire (dans #2) ou en forçant le déplacement avec std::move (dans #3)


    @Manticore
    Réponse qui marche toujours : cela dépend

    Si tu t'intéresse qu'à la sémantique, la première version si tu as des objets à sémantique d'entité, la seconde si tu as une sémantique de valeur.

    Si tu t'intéresse aux perfs... fais du profiling
    Le risque de la seconde version du code, en termes de perfs, n'est pas la copie lors de la création d'un nouvel élément. C'est surtout que tu risques d'avoir, lors d'un pusk_back, un redimensionnement du vector, donc réallocation + copie de la totalité du vector. La première version du code permet d'éviter la copie des chaînes, au prix d'une modification de la sémantique.
    Mais cela est à vérifier en pratique : si tu as un tableau qui contient 10 chaines de 10 caractères et que tu fais un push 1 fois par mois, même si en théorie la version avec pointeur est plus performante, le gain réel sera nul.

    Donc dans l'ordre :
    * C++11 si tu peux
    * profiling pour vérifier l'utilisation réelle
    * modifier la politique de dimensionnement de tes vectors
    * utiliser des pointeurs "masqués" pour garder la même sémantique en bénéficiant des pointeurs (string avec COW, boost.ptr_vector, vector<unique_ptr>)
    * faire du code moche

  4. #4
    Membre chevronné

    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2009
    Messages
    377
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Novembre 2009
    Messages : 377
    Par défaut
    Merci beaucoup de ces informations très clair

    J'ai tous les éléments pour faire un choix.

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

Discussions similaires

  1. Bonnes pratiques de protections individuelles
    Par Community Management dans le forum Sécurité
    Réponses: 23
    Dernier message: 11/06/2024, 11h23
  2. std::sort() sur std::vector()
    Par tut dans le forum SL & STL
    Réponses: 20
    Dernier message: 05/01/2005, 19h15
  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