le “rendement” de mot-clé pour le C++, Comment Retourner un Itérateur de ma Fonction?
Considérons le code suivant.
std::vector<result_data> do_processing()
{
pqxx::result input_data = get_data_from_database();
return process_data(input_data);
}
std::vector<result_data> process_data(pqxx::result const & input_data)
{
std::vector<result_data> ret;
pqxx::result::const_iterator row;
for (row = input_data.begin(); row != inpupt_data.end(); ++row)
{
//somehow populate output vector
}
return ret;
}
Tandis que je pensais à savoir si ou non je pouvais attendre de la Valeur de Retour d'Optimisation (RVO) pour arriver, j'ai trouvé cette réponse par Jerry Cercueil [c'est moi qui souligne]:
Au moins de l'OMI, il est généralement une mauvaise idée, mais pas pour des raisons d'efficacité. C'est une mauvaise idée parce que la fonction en question doit généralement être écrit comme un algorithme générique qui produit sa sortie via un itérateur. Presque n'importe quel code qui accepte ou renvoie d'un conteneur au lieu d'opérer sur les itérateurs doit être considérée comme suspecte.
Ne vous méprenez pas: il y a des fois il est logique de passer autour de la collection de comme des objets (par exemple, des chaînes de caractères), mais pour l'exemple cité, j'avais envisager l'adoption ou le retour de l'vecteur une mauvaise idée.
Avoir un Python de fond, j'aime les Générateurs de beaucoup. En fait, si on Python, j'aurais écrit au-dessus de fonctionner comme un Générateur, c'est à dire pour éviter la nécessité de traiter l'ensemble des données avant toute autre chose qui pourrait arriver. Par exemple, comme ceci:
def process_data(input_data):
for item in input_data:
# somehow process items
yield result_data
Si j'ai correctement interprété Jerry Cercueils remarque, c'est ce qu'il a suggéré, n'est-ce pas? Si oui, comment puis-je mettre en œuvre cette en C++?
- Il suffit de retourner le vecteur, c'est très bien. (N)RVO seront plus susceptibles de prendre soin de cela, et en C++11 sémantique de déplacement va faire quand (N)RVO ne le fait pas. Aussi,
return process_data(get_data_from_database());
. Malheureusement, C++ n'ont pas leyield
fonctionnalité. 🙁 - "Presque tout le code qui accepte ou retourne un conteneur au lieu d'opérer sur les itérateurs doit être considérée comme suspecte." Je dirais qu'avec cette. C'est certainement de bon conseil, mais le désir de rendre le code indépendant du type de conteneur est souvent erronée et ne sont pas interchangeables, sauf dans la syntaxe...
Vous devez vous connecter pour publier un commentaire.
Non, ce n'est pas ce que Jerry signifie, du moins pas directement.
yield
en Python met en œuvre coroutines. C++ n'y en a pas (mais ils peuvent bien sûr être émulé mais c'est un peu impliqué si c'est fait proprement).Mais ce que Jerry signifie simplement que vous devez passer à une sortie itérateur qui est écrit à:
Et l'appeler:
Je ne suis pas convaincu qu'il est généralement mieux que de simplement retourner le vecteur.
process_data
double - peut-être sur différentes données d'entrée - mais le résultat dans le mêmeresult
objet. Et l'efficacité est pourquoi vous utilisez le C++, en premier lieu, non? Cela mis à part, vous permettre à l'appelant d'utiliser un allocateur personnalisé pour le conteneur.result
pourrait être un jeu par exemple.Il y a un post de blog de Boost.Asio auteur Chris Kohlhoff à ce sujet: http://blog.think-async.com/2009/08/secret-sauce-revealed.html
Il simule
yield
avec une macroCe doit être utilisé en conjonction avec un
coroutine
classe. Voir le blog pour plus de détails.Lorsque vous analysez quelque chose de manière récursive ou lorsque le traitement a unis, le générateur de modèle pourrait être une bonne idée et de simplifier le code grandement—on ne peut pas facilement itérer alors, et, normalement, les rappels sont l'alternative. Je veux avoir
yield
, et de trouver que Coup de pouce.Coroutine2 a l'air de bien utiliser maintenant.Le code ci-dessous est un exemple de
cat
fichiers. Bien sûr, il est dénué de sens, jusqu'à l'endroit où vous voulez traiter le texte des lignes plus loin:J'ai trouvé qu'un istream-comme le comportement revient à ce que j'avais à l'esprit. Considérez les points suivants (non testé) code:
Maintenant je peux le faire, comme le montre l'exemple suivant:
De cette façon, l'acquisition des données est d'une certaine manière découplée de la transformation et de l'est de ce fait autorisé à se produire paresseux/asynchrone. C'est, je pourrais traiter les articles qu'ils arrivent et je n'ai pas à attendre jusqu'à ce que le vecteur est remplie complètement comme dans l'autre exemple.