156 votes

Une manière efficace de retourner un std::vector en c++.

Combien de données sont copiées, lors du retour d'un fichier std::vector dans une fonction et quelle sera l'ampleur de l'optimisation si l'on place le vecteur std::vector en free-store (sur le tas) et que l'on renvoie un pointeur à la place, c'est-à-dire si :

std::vector *f()
{
  std::vector *result = new std::vector();
  /*
    Insert elements into result
  */
  return result;
} 

plus efficace que :

std::vector f()
{
  std::vector result;
  /*
    Insert elements into result
  */
  return result;
} 

?

0voto

harrypotter0 Points 578
vector<string> getseq(char * db_file)

Et si vous voulez l'imprimer sur main(), vous devez le faire dans une boucle.

int main() {
     vector<string> str_vec = getseq(argv[1]);
     for(vector<string>::iterator it = str_vec.begin(); it != str_vec.end(); it++) {
         cout << *it << endl;
     }
}

-2voto

Aussi agréable que soit le "retour par valeur", c'est le genre de code qui peut conduire à l'erreur. Considérez le programme suivant :

    #include <string>
    #include <vector>
    #include <iostream>
    using namespace std;
    static std::vector<std::string> strings;
    std::vector<std::string> vecFunc(void) { return strings; };
    int main(int argc, char * argv[]){
      // set up the vector of strings to hold however
      // many strings the user provides on the command line
      for(int idx=1; (idx<argc); ++idx){
         strings.push_back(argv[idx]);
      }

      // now, iterate the strings and print them using the vector function
      // as accessor
      for(std::vector<std::string>::interator idx=vecFunc().begin(); (idx!=vecFunc().end()); ++idx){
         cout << "Addr: " << idx->c_str() << std::endl;
         cout << "Val:  " << *idx << std::endl;
      }
    return 0;
    };
  • Q : Que se passe-t-il lorsque la commande ci-dessus est exécutée ? R : Un coredump.
  • Q : Pourquoi le compilateur n'a-t-il pas détecté l'erreur ? R : Parce que le programme est syntaxiquement, mais pas sémantiquement, correct.
  • Q : Que se passe-t-il si vous modifiez vecFunc() pour retourner une référence ? R : Le programme s'exécute jusqu'au bout et produit le résultat attendu.
  • Q : Quelle est la différence ? R : Le compilateur ne doit pas n'a pas à créer et à gérer des objets anonymes. Le programmeur a demandé au compilateur d'utiliser exactement un objet pour l'itérateur et pour la détermination du point d'arrivée, plutôt que deux objets différents comme le fait l'exemple brisé.

Le programme erroné ci-dessus n'indiquera aucune erreur même si l'on utilise les options de rapport de GNU g++ -Wall -Wextra -Weffc++.

Si vous devez produire une valeur, alors ce qui suit fonctionnera au lieu d'appeler vecFunc() deux fois :

   std::vector<std::string> lclvec(vecFunc());
   for(std::vector<std::string>::iterator idx=lclvec.begin(); (idx!=lclvec.end()); ++idx)...

La méthode ci-dessus ne produit pas non plus d'objets anonymes pendant l'itération de la boucle, mais nécessite une éventuelle opération de copie (qui, comme certains le font remarquer, pourrait être optimisée dans certaines circonstances). Mais la méthode de référence garantit qu'aucune copie ne sera produite. Croire que le compilateur effectuera la RVO n'est pas un substitut pour essayer de construire le code le plus efficace possible. Si vous pouvez faire en sorte que le compilateur n'ait pas à effectuer de RVO, vous avez une longueur d'avance.

-2voto

Amruth A Points 225
   vector<string> func1() const
   {
      vector<string> parts;
      return vector<string>(parts.begin(),parts.end()) ;
   } 

Cela reste efficace à partir de c++11 car le compilateur utilise automatiquement le déplacement au lieu de faire une copie.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X