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

C++ Discussion :

Optimisation vitesse pure


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre expérimenté Avatar de Kujara
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    262
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 262
    Par défaut Optimisation vitesse pure
    Ok, topic simple : ça fait longtemps que je programme, et ça fait un peu trop longtemps que je vois des gens taper du code pas optimisé du tout.

    Donc, je souhaiterai partager les techniques simples que j'ai apprises au fil des ans.

    A noter : j'optimise plutot en vitesse pure, vu que c'est ce dont j'ai besoin le plus souvent.

    Participation a ce sujet : si vous voulez proposer des solutions differentes ou si vous trouvez que mes solutions sont mauvaises, des arguments sont obligatoires.Je ne suis pas parfait, mes algos non plus, mais ne venez pas me dire "c'est plus lent que ce que j'ecris" sans arguments pour le justifier ...


    Page 1 : ici
    Page 2 : Quelques techniques d'implementation, en vrac


    Sous-sujet du jour : utilisation de la STL, version speed.


    Généralités :
    Pour les iterateurs , la preincrémentation est toujours plus rapide que la post incrémentation.

    En terme de vitesse pure : tableau de base > vector > list > [ set > map > multimap ] pour du parcours simple.
    Set / Map > Multimap > [ vector / tableau ] > list pour une recherche par clef.
    Set > [ vector / tableau ] > list > [ map / multimap ] pour une recherche par element( sans connaitre la clef).

    La FAQ C++ a un joli diagramme pour vous aider a choisir votre conteneur

    La complexité des operations sur les conteneurs de la stl sont dispos sur le net.

    i++ et ++i, si i est un type de base ( int , float, etc), est strictement equivalent en vitesse.

    Insertion d'un element dans une map / set :
    Edit : version optimisé par Screetch, merci.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    const std::pair< MapType::iterator, bool > & result = map.insert( clef, element );
    if(!result.second)
    {
    //Element existant déja, result.first pointe dessus
    }
    Si vous savez déja que l'element n'existe pas ( premier remplissage d'une map par exemple) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    map.insert( MapType::value_type( clef , element ) );
    A noter que ça revient presque au même que la version precedante. Par contre c'est plus court a ecrire.

    A noter aussi : l'operateur [] sur une map est a eviter. En effet il crée un element avec le constructeur par default, puis vous renvoie la reference, que là vous changez. Donc construction par default + copie au lieu de construction par copie.

    Parcours d'une map / set :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    MapType :: iterator iter = map.begin();
    const MapType :: iterator & iend = map.end();
    for( ; iter != iend ; ++ iter )
    {
    //boucle
    }
    Parcours d'un vector:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    unsigned int imax = vector.size();
    for( unsigned int i = 0 ; i < imax ; ++ i )
    {
    boucle avec vector[i]
    }

    Vider une map / set / multimap
    Si votre map ne contient pas de pointeurs : map.clear() suffit.
    Sinon :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    MapType :: iterator iter = map.begin();
    const MapType :: iterator & iend = map.end();
    for( ; iter != iend ; ++ iter )
    {
     delete iter->second;
    }
    map.clear();
    Simple recherche sur map / set :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    const MapType :: iterator & ifind = map.find( clef );
    if( ifind != map.end() )
    {
    //code
    }
    Optimisations Generales :

    Optimisations Basiques :
    En vrac :

    -> Utilisez les reference sur les structures / classes. C'est facile de l'oublier, et on le paye d'une copie. Tres couteux quand on l'oublie sur une map ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void fonction( std::string p_name )
    ->
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void fonction( const std::string & p_name )
    Virez le const si vous souhaitez modifier le parametre.

    -> Utilisez les liste d'initialisation dans les constructeurs
    Un exemple vaut plus qu'un discours:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class A
    {
    private:
    std::string m_name;
    public:
    A( const std::string & p_name ){m_name = p_name;}
    };
    Fait appel au constructeur par defaut de std::string, puis fait une copie.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class A
    {
    private:
    std::string m_name;
    public:
    A( const std::string & p_name ) : m_name (p_name){}
    };
    Ne fait appel qu'au constructeur par copie.


    -> Evitez les objets temporaires si possible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Vector3 V3_Add( const Vector3 & p_a , const Vector3 & p_b )
    {
    Vector3 a;
    a.x = p_a.x + p_b.x;
    a.y = p_a.y + p_b.y;
    a.z = p_a.z + p_b.z;
    return a;
    }
    Profitez des constructeurs avec parametres :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Vector3 V3_Add( const Vector3 & p_a , const Vector3 & p_b )
    {
    return Vector3( p_a.x + p_b.x  , p_a.y + p_b.y , p_a.z + p_b.z )
    }
    -> Utilisez les references temporaires :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void Function( const std::string & p_filename , const std::string & p_directory )
    {
    std::string l_fullname;
    l_fullname = p_filename + p_directory;
    }
    Ici, vous faitent appel a un constructeur par defaut, puis une copie.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void Function( const std::string & p_filename , const std::string & p_directory )
    {
    const std::string & l_fullname = p_filename + p_directory;
    }
    Alors que la, plus de constructeur pour rien, plus de copie.
    Inutilisable si vous devez faire des modifications sur l_fullname, par contre.

    -> Profitez des constructeurs par copie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void Function( const std::string & p_filename )
    {
    std::string l_name;
    l_name = p_filename;
    }
    Admettons que vous ayez besoin de l_name pour le modifier.Vous auriez du ecrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void Function( const std::string & p_filename )
    {
    std::string l_name = std::string(p_filename);
    }
    Le compilateur optimisera en faisant appel directement au constructeur par copie, plutot que l'habituel couple constructeur defaut + copie.

    -> Utilisation des tableaux a 2 dimensions :
    Attention a cela.Si les 2 dimensions sont assez faibles, preferez un tableau a une dimension ( remplacez un 16x16 par un 256 directement), ça evite des allocations mémoires en plus, des dereferencements compliqués, des boucles for imbriquées, etc.
    Exception : les très grand tableaux, du genre 4000 x 4000.doubles.
    Dans la pluspart des cas pour ce genre de tableaux, ils sont tellements gros qu'il ne rentrent pas dans le cache du proc, donc le decouper en morceaux peut eventuellement etre utile. A tester au cas par cas.

    -> Groupez les traitements sur une donnée.
    Pour avoir testé moi même :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	X = caller->m_childs[0];
    	Y = caller->m_childs[1];
    	if(X->m_hasFunction)X->m_function(X);
    	if(Y->m_hasFunction)Y->m_function(Y);
    Est plus rapide ( d'un cycle proc exactement, d'apres mes tests), que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	X = caller->m_childs[0];
    	if(X->m_hasFunction)X->m_function(X);
    	Y = caller->m_childs[1];
    	if(Y->m_hasFunction)Y->m_function(Y);
    Probablement parceque m_childs reste dans les registres dans la premiere version et pas dans la deuxième.



    Choses a ne pas faire : : ( liste non exhaustive ).
    A noter que cette liste n'est valable que sur des compilateurs performants( vc++, gcc), si vous travaillez sur des compilos alternatifs, a vous de tester.

    -> Remplacer les multiplications par des decalages de bits +/- additions.

    -> Utiliser ++i au lieu de i++ sur des types de base( int, float).

    -> Remplacer un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    const int a = 4;
    const int b = 3;
    const int c = a * b
    Par const int c = 12;
    Le compilateur optimise de lui même tout ce qui est const a la compilation, et tout les calculs qui en découlent.Remplacer a * b par son resultat ne sert qu'a perdre de vu que c'est le resultat d'un calcul et non un chiffre "magique".

    -> Utiliser __forceinline sans etre sur ce que l'on fait. Le compilateur est souvent meilleur que nous a ce jeu la.

    -> Derouler les boucles. Exception pour les boucles courtes ( genre 3 tours).

    -> Faire des boucles for avec des char et des short. Dans ce genre de boucle, l'index est geré par les registres.Les registres sont 32 bits minimum, donc int ou unsigned int.

    -> Faire des boucles for du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for( unsigned int i = MAX ; i ; --i ){code;}
    Une legende urbaine court selon laquelle decrementer un entier et verifier par rapport a zero est plus rapide que le bon vieux for ( i = 0 ; i < MAX ; i++ ). En fait non, puisque le compilateur l'optimise pour vous...

  2. #2
    screetch
    Invité(e)
    Par défaut
    pour l'insertion dans un map :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    typedef std::map< key, value > monmap;
    std::pair< monmap::iterator, bool > result = dico.insert( clef, element );
    if(!result.second) //l'insertion n'a pas ete faite car l'element existait deja
      result.first->second = element; // remplaces l'element en question si on souhaitait l'ecraser
    ce code est plus efficace je pense car il ne fait qu'une recherche dans le dico; le tiens en fait deux.

  3. #3
    Membre expérimenté Avatar de Kujara
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    262
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 262
    Par défaut
    Citation Envoyé par screetch Voir le message
    le tiens en fait deux.
    Justement non ^^.
    Mon insert utilise l'iterateur renvoyé par lower_bound.
    Cela permet l'insertion sur la map en temps constant.

    Mais effectivement, ta méthode est probablement plus rapide, merci.

    D'ailleurs tu peux changer un truc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const std::pair< monmap::iterator, bool > & result = dico.insert( clef, element );

  4. #4
    Membre émérite
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    780
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mai 2006
    Messages : 780
    Par défaut
    utiliser l'opérateur [] pour des insertions où l'on veut écraser la valeur existante si elle existe, c'est si coûteux que ça?

  5. #5
    Membre expérimenté Avatar de Kujara
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    262
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 262
    Par défaut
    Citation Envoyé par nikko34 Voir le message
    utiliser l'opérateur [] pour des insertions où l'on veut écraser la valeur existante si elle existe, c'est si coûteux que ça?
    Non, c'est pas tant couteux que ça. Juste un tout petit peu(quelques operations en plus).Mais bon, a force d'accumuler des "petit peu plus lent", tu te retrouve avec un programme beaucoup plus lent ^_^.

    Et la méthode normale est plus claire( avec separation evidente des cas où tu insere et ceux où tu remplace).

    Conclusion : l'operateur [] ça marche très bien dans du code pas critique.

    J'en profite pour enchainer sur une note importante :

    Pour les vectors, l'operator [] est plus rapide que la fonction at().
    Par contre, at() verifie l'index qu'on lui passe, pas [] .

  6. #6
    screetch
    Invité(e)
    Par défaut
    Citation Envoyé par Kujara Voir le message
    D'ailleurs tu peux changer un truc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const std::pair< monmap::iterator, bool > & result = dico.insert( clef, element );
    euh non je pense pas, la valeur est créée par la fonction, il n'est pas possible de garder seulement une reference dessus, il faut la copier!

  7. #7
    Membre expérimenté Avatar de Kujara
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    262
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 262
    Par défaut
    Citation Envoyé par screetch Voir le message
    euh non je pense pas, la valeur est créée par la fonction, il n'est pas possible de garder seulement une reference dessus, il faut la copier!
    C'est non seulement possible mais plus rapide, pour ce coup la.

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ClassA fonction()
    {
    	return ( ClassA () );
    }
     
    void Func2()
    {
    ClassA  l_refA;
    l_refA = blah();
    }
    Crée un objet Class A, puis un autre, puis copie, puis detruit les 2.

    Alors que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void Func2()
    {
    const ClassA  & l_refA = blah();
    }
    Ne passe qu'une fois dans le constructeur, et une fois dans le destructeur.

    Testable sous gcc qui respecte les standards, donc c'est autorisé.

    D'apres ce que je comprends, le compilateur etends la lifetime de ton objet renvoyé par la fonction, au scope de la reference.

    Attention par contre, une reference non const n'est pas autorisé( modification d'un objet temporaire).

  8. #8
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Salut,

    Ca c'est faux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if( ifind == map.end() || ifind->first != clef )
    La bonne version est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if( ifind == map.end() || !(map.key_comp()(ifind->first, clef)) )
    Egalité et équivalence sont deux concepts distincts, voir par exemple Effective STL sur ce sujet, et plus particulièrement items 19 et 45.

    MAT.

  9. #9
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par Kujara Voir le message
    Parcours d'une map / set / vector :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    MapType :: iterator iter = map.begin();
    const MapType :: iterator & iend = map.end();
    for( ; iter != iend ; ++ iter )
    {
    //boucle
    }
    Pour un vector c'est faux (du moins pour visual, gcc c'est a verifier, pour les autre cela va dépendre de leur implémentation je pense).
    Pour un parcours sur un vector il faut utiliser for_each. Ou parcourir le tableau comme en C.
    La différence est que le for_each va transformer l'iterateur en pointeur. Ce qui reviens à parcourir la mémoire comme un tableau en C. Utilisé comme tu le montre, l'iterator fait plus de chose (genre des test) et est donc moins rapide.
    Tu peut faire le teste, c'est bluffant.

    En toute honnêteté, y as pas vraiment de super méthode pour être rapide ( sauf si tu code en asm), le compilot fera ce qu'il veut et optimisera comme il veut.
    Pour base, je dirait utiliser les algo le plus possible. Il savent mieux que toi comment optimiser ton code. Regarde le livre EFFECTIVE STL

  10. #10
    Membre expérimenté Avatar de Kujara
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    262
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 262
    Par défaut
    Citation Envoyé par Mongaulois Voir le message
    Pour un vector c'est faux (du moins pour visual, gcc c'est a verifier, pour les autre cela va dépendre de leur implémentation je pense).
    C'est pour ça que j'ai mis la 2eme solution pour les vectors.
    Citation Envoyé par Mongaulois Voir le message
    En toute honnêteté, y as pas vraiment de super méthode pour être rapide ( sauf si tu code en asm), le compilot fera ce qu'il veut et optimisera comme il veut.
    Pour base, je dirait utiliser les algo le plus possible. Il savent mieux que toi comment optimiser ton code. Regarde le livre EFFECTIVE STL, que tu peut même trouve en cherchant sur google au format pdf. Mais je sait pas si c'est légale
    Je suis loin d'avoir finit de vous donner ma liste d'optimisation possibles, et la stl n'est qu'un petit bout de ce que j'ai prevu.

    Et sache que tu a tort.Le compilateur est puissant, ton cerveau l'est plus, même sans inline asm.

  11. #11
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Tes "optimisations" ne servent en général à rien. L'optimiseur est déjà parfaitement capable de calculer la valeur une seule fois et pas à chaque boucle par lui-même. (de toutes façons la fonction est si simple qu'elle sera sûrement inlinée).
    Ensuite un tableau et un vecteur, ça a exactement les mêmes performances. Ça génère le même code assembleur.

    Cette solution depends de la plateforme apparemment, car size() n'est pas guaranti en temps constant.Si votre implementation le fait en constant( msvc++ par exemple ), c'est plus rapide. Sinon, c'est plus lent.
    std::vector<T>::size est toujours en temps constant.
    Le seul conteneur où ce n'est pas toujours le cas, c'est std::list, à cause de std::list<T>::splice.

  12. #12
    Membre expérimenté Avatar de Kujara
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    262
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 262
    Par défaut
    std::vector<T>::size est toujours en temps constant.
    Le seul conteneur où ce n'est pas toujours le cas, c'est std::list, à cause de std::list<T>::splice.
    Pour vector, oui. Pour les autres,trouve moi une source officielle qui confirme et je l'integrerais dans le sujet ?Merci d'avance ^^.

    Ensuite un tableau et un vecteur, ça a exactement les mêmes performances. Ça génère le même code assembleur.
    Identique ? Tu m'expliquera en quoi tu peux agrandir un tableau alloué avec un new ......

    Boost a un conteneur a peu pres identique, le boost::array. Mais vector a toujour été totalement different des tableaux.

    Apres, si tu parlais juste question acces aux données via l'operateur [], oui, je suis d'accord.

    L'optimiseur est déjà parfaitement capable de calculer la valeur une seule fois et pas à chaque boucle par lui-même.
    Prouve le moi, s'il te plait.


    Note au passage : j'ai rajouté des trucs sur le premier post.

  13. #13
    screetch
    Invité(e)
    Par défaut
    sans vouloir etre chiant ^^ (si un peu) concernant le stockage de ta valeur de retour,

    lorsque je fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    A getA() { return A(); }
    alors il faudra que l'objet A soit construit puis passé a la fonction appelante, et ce quel que soit l'utilisation du A en question plus tard.

    si je fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main()
    {
      getA();
      return 0;
    }
    il faudra quand meme que le A soit construit et donné a main, qui devra alors le detruire.

    lorsque tu fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main()
    {
      A a = getA();
      return 0;
    }
    tu ne fais que nommer ce que la fonction getA renvoie, car de toute facon quoi qu il arrive A a du etre passée a l'appelant

    et lorsque tu fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main()
    {
      const A& a = getA();
      return 0;
    }
    tu ne fais que conne la premiere fonction a savoir un stockage temporaire non nommé, puis un alias par reference dessus

    c'est a dire que dans les 3 cas (utilisé, stocké ou par reference) la fonction a crée l'objet et l'a passé a main, qui va la stocker teporairement. le reste, c'est : soit c'est stocké anonymement (et tu peux avoir une reference dessus) soit tu le nommes explicitement.

    en gros, const-reffer le retour d'une methode n'apporte rien en terme de vitesse et alourdit l'ecriture.

  14. #14
    screetch
    Invité(e)
    Par défaut
    concernant les iterateurs, gaulois, c'est du a la presence dans la lib visual de _HAS_ITERATOR_DEBUGGING. il faut definir cette macro a 0 si tu veux desactiver les checks d'iterateur tres lents.

    les algos de la STL sont plus rapide car ils checkent begin(), end() et passent la main a la version qui ne checke rien. lorsque tu ecris la boucle a la main, tu vas faire verifier (sans le savoir) deux iterateurs par boucle, l'iterateur courant et end().

    n'oubliez pas de definir _HAS_ITERATOR_DEBUGGING a 0 en release... et de tester en debug ^^

  15. #15
    Membre expérimenté Avatar de Kujara
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    262
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 262
    Par défaut
    Citation Envoyé par screetch Voir le message
    en gros, const-reffer le retour d'une methode n'apporte rien en terme de vitesse et alourdit l'ecriture.
    Ok, tu m'a mis le doute, donc je suis parti tester.

    Conclusions : dans le cas d'une méthode qui renvoie une instance, donc style return (A()); , effectivement ça ne sert a rien.

    Par contre, si ta fonction renvoie une reference, la c'est parfaitement justifié( cela donne lieu a un constructeur par copie si tu le recupere avec un objet normal plutot qu'une const ref).

    Donc, si tu peux utiliser une const ref, et si tu n'est pas sur que la fonction renverra toujours un nouvel objet plutot qu'une reference, un const object & est preferable, non ?

    Bref, personellement j'utilise les const ref dès que possible, comme ça j'ai pas a me poser la question ^^.

  16. #16
    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 : 50
    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
    Par défaut
    Citation Envoyé par Kujara Voir le message
    std::vector<T>::size est toujours en temps constant.
    Le seul conteneur où ce n'est pas toujours le cas, c'est std::list, à cause de std::list<T>::splice.
    Pour vector, oui. Pour les autres,trouve moi une source officielle qui confirme et je l'integrerais dans le sujet ?Merci d'avance ^^.
    Extrait du standard (désolé pour la mise en forme, à la base, c'est un tableau...) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    expression | return type | operational semantics | assertion/note | complexity
    a.size()   | size_type   | a.end() - a.begin()   |                | (Note A)
     
    Those entries marked ‘‘(Note A)’’ should have constant complexity.
    Donc, ce n'est pas garanti à 100% (emploi de should), mais très fortement conseillé.
    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.

Discussions similaires

  1. Optimisation Vitesse d'Exécution Calcul matriciel
    Par olivier21c dans le forum Langage
    Réponses: 33
    Dernier message: 02/09/2011, 11h46
  2. Optimisation & Vitesse d'execution ?
    Par MaXOhBalle dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 16/09/2009, 09h44
  3. optimiser vitesse application
    Par petitours dans le forum Access
    Réponses: 3
    Dernier message: 03/04/2008, 15h25
  4. Réponses: 5
    Dernier message: 20/11/2007, 08h48
  5. optimisation vitesse
    Par WaM dans le forum C
    Réponses: 7
    Dernier message: 09/01/2006, 23h43

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