web-dev-qa-db-fra.com

Initialisation de std :: vector de std :: string

En travaillant dans un projet avec du code hérité, j'ai trouvé cette fonction:

std::vector<std::string> Object::getTypes(){
    static std::string types [] = {"type1","type2", "type3"};
    return std::vector<std::string> (types , types +2);
}

J'aurais probablement écrit ceci comme:

std::vector<std::string> Object::getTypes(){
    std::vector<std::string> types;
    types.Push_back("type1");
    types.Push_back("type2");
    types.Push_back("type3");
    return types;
}

Est-ce simplement un choix de style ou y at-il quelque chose qui me manque? Toute aide serait grandement appréciée. Désolé si c'est trop basique.

Mise à jour: En fait, différentes classes qui surchargent la même méthode le font d'une manière ou d'une autre, c'est donc encore plus ambigu. Je les ferais tous pareil mais préférerais la meilleure approche, s'il en existe une.


Modifier

Veuillez noter que le code hérité ci-dessus est incorrect car il initialise le vecteur avec uniquement les deux premiers éléments du tableau. Cependant, cette erreur a été discutée dans les commentaires et doit donc être préservée.

La bonne initialisation aurait dû se lire comme suit:

...
    return std::vector<std::string> (types, types + 3);
...
9
Andres Bucci

Le tableau types du premier exemple est déclaré statique. Cela signifie qu’il n’existe qu’une fois en mémoire. Donc, il y a trois options pour ce qu'il faut retourner et ils vivent dans la mémoire statique. Ensuite, lorsque vous créez le vecteur à renvoyer, vous pouvez allouer sa mémoire en un seul coup en transmettant le début et la fin du tableau sous forme d'itérateurs.

En procédant de cette façon, vous n'avez pas d'appels successifs à Push_back, ce qui signifie que le vecteur n'aura pas à réaffecter son bloc de mémoire interne.

De même, lorsque le vecteur est construit dans le cadre de l'appel de retour, les compilateurs plus anciens auront plus de facilité à effectuer l'optimisation des valeurs de retour .

1
Anthony

Si vous avez un compilateur et une bibliothèque compatibles C++ 11, le retour d'une liste d'initialisateurs devrait suffire:

std::vector<std::string> Object::getTypes(){
    return {"type1","type2", "type3"};
}
9

Le code que vous avez trouvé est plus efficace (car types[] n'est attribué qu'une seule fois et Push_back peut/entraînera des réallocations). La différence est cependant marginale, et à moins que vous appeliez getTypes dans une boucle (relativement grande), cela ne devrait pas avoir d'importance (et probablement pas beaucoup, même si vous l'appelez dans une grande boucle).

En tant que tel, à moins que cela ne crée un problème de performance concret, c'est un choix de style.

5
utnapistim

Fondamentalement, c'est un choix de style. Je ferais probablement quelque chose de plus semblable à

std::vector<std::string> Object::getTypes(){
    static std::string types [] = {"type1","type2", "type3"};
    return std::vector<std::string> (types, 
                   types + (sizeof(types)/sizeof(std::string)) );
}

ce qui vous permet de changer le nombre de choses dans les types, sans avoir à vous rappeler de mettre à jour le nombre dans la ligne suivante.

3
Michael Kohne

Une des raisons pour lesquelles j'aime utiliser ce style d'initialisation avec des itérateurs (et les listes d'initialisation et d'initialisation uniformes de C++ 11) est qu'il permet de séparer les données du code.

Répéter plusieurs fois Push_back me fait mal, car j’ai désespérément besoin de le refactoriser. De même, lorsque vous avez vraiment besoin d'initialiser le conteneur avec des données, vous souhaitez voir une liste des données et non pas un code qui génère des données. La méthode que vous avez trouvée dans la version originale correspond mieux à ce principe.

0
user529758