74 votes

Quel est le plus efficace: renvoyer une valeur par rapport à Passer par référence?

Je suis actuellement en train d'étudier une écriture efficace de code C++, et sur la question des appels de fonction, une question vient à l'esprit. La comparaison de cette pseudo-code de la fonction:

not-void function-name () {
    do-something
    return value;
}
int main () {
    ...
    arg = function-name();
    ...
}

avec cela, sinon identique, du pseudo-code de la fonction:

void function-name (not-void& arg) {
    do-something
    arg = value;
}
int main () {
    ...
    function-name(arg);
    ...
}

Quelle version est la plus efficace, et dans quelle mesure (temps, mémoire, etc.)? Si elle dépend, alors où serait la première à être plus efficace et où serait la plus efficace sera la deuxième?

Edit: Pour le contexte, cette question est limitée au matériel indépendant de la plate-différences, et pour la plupart des logiciels de trop. Sont-il indépendant de l'ordinateur différence de performance?

Edit: je ne vois pas en quoi cela est un doublon. L'autre question est de comparer le passage par référence (prev. code) de passage par valeur (ci-dessous):

not-void function-name (not-void arg)

Ce qui n'est pas la même chose que ma question. Mon objectif n'est pas de qui est le meilleur moyen de passer en argument à une fonction. Mon accent est mis sur ce qui est le meilleur moyen de passer à sortir un résultat à une variable à partir de l'extérieur de la portée.

26voto

arodriguezdonaire Points 2660

Tout d'abord, prendre en compte que la restitution d'un objet sera toujours plus lisible (et très similaire à la performance) que de l'avoir passé par référence, ce qui pourrait être plus intéressant pour votre projet de retourner l'objet et d'accroître la lisibilité, sans avoir d'importantes différences de rendement. Si vous voulez savoir comment faire pour avoir le coût le plus bas, le truc, c'est quoi avez-vous besoin de revenir:

  1. Si vous avez besoin de retourner un simple ou un objet de base, le rendement est similaire dans les deux cas.

  2. Si l'objet est tellement vaste et complexe, de retour, il aurait besoin d'une copie, et il pourrait être plus lente que d'avoir comme un paramètre référencé, mais il pourrait consacrer moins de mémoire je pense.

Vous devez penser de toute façon que les compilateurs faire beaucoup d'optimisations qui font à la fois des performances très similaires. Voir Copie D'Élision.

9voto

David Haim Points 3696

Eh bien, il faut comprendre que la compilation n'est pas facile d'affaires. il y a beaucoup de considération qui est prise lorsque le compilateur compile le code.

On ne peut pas simplement répondre à cette question parce que le C++ standard ne fournit pas de standard ABI (résumé binary interface), de sorte que chaque compilateur est autorisé à compiler le code ce qu'il veut et vous pouvez obtenir des résultats différents dans chaque compilation.

Par exemple, sur certains de ces projets C++ est compilé pour la gestion de l'extension de Microsoft CLR (C++/CX). puisque tout y est déjà une référence à un objet sur le tas, je suppose qu'il n'y a pas de différence.

La réponse n'est pas simple pour géré par les nations unies compilations. plusieurs quaestion viennent à l'esprit quand je pense à la "Va XXX courir plus vite YYY?", par exemple:

  • Est vous vous opposez défaut constructible?
  • Est-ce que votre compilateur soutenir le retour à la valeur de l'optimisation?
  • Est-ce que votre support objet de Copie uniquement sémantique, ou les deux, de copie et de déplacement?
  • Est l'objet emballé dans contigious manière (par exemple, std::array) ou il a pointeur vers quelque chose sur le tas? (par exemple, std::vector)?

Si je donne l'exemple concret, ma conjecture est que sur MSVC++ et GCC, de revenir std::vector , en valeur, sera le comme le passage par référence, en raison de la r-valeur-de l'optimisation, et seront un peu (en quelques nanosecondes) plus rapide que le renvoi de l'vecteur par la déplacer. cela peut être complètement différent sur Clang, par exemple.

finalement, le profilage est la seule véritable réponse ici.

8voto

Simple Points 4460

Retour de l'objet doit être utilisé dans la plupart des cas en raison d'une optimsation appelé copie élision.

Toutefois, selon la façon dont votre fonction est destinée à être utilisée, il peut être préférable de passer de l'objet par référence.

Regardez - std::getline "par exemple, qui prend un std::string par référence. Cette fonction est destinée à être utilisée comme une condition de boucle et continue de remplir un std::string jusqu'à ce que EOF est atteint. En utilisant le même std::string permet à l'espace de stockage de l' std::string pour être réutilisés dans chaque itération de boucle, ce qui réduit considérablement le nombre d'allocations de mémoire qui doivent être effectuées.

5voto

Vality Points 2294

Certaines réponses ont touché, mais je tiens à souligner, à la lumière de la modifier

Pour le contexte, cette question est limitée au matériel indépendant de la plate-différences, et pour la plupart des logiciels de trop. Sont-il indépendant de l'ordinateur différence de performance?

Si c'est les limites de la question, la réponse est qu'il n'y a pas de réponse. Le c++ spec ne précise pas comment le retour d'un objet ou d'un passage par référence est mis en œuvre performance sage, seul le semmantics de ce qu'ils font tous les deux en termes de code.

Un compilateur est donc gratuit pour optimiser un à un code identique que les autres assumging ce n'est pas de créer une différence perceptible pour le programmeur.

À la lumière de cela, je pense qu'il est préférable d'utiliser la méthode la plus intuitive de la situation. Si la fonction est en effet "retour" à un objet comme le résultat d'une tâche ou d'une requête, de retour, tandis que si la fonction est d'effectuer une oppération sur un objet possédé par le code extérieur, passage par référence.

Vous ne pouvez pas généraliser performance sur ce, pour commencer, faire tout ce qui est intuitif et voir comment votre système cible et le compilateur optimise elle. Si, après le profilage et la découverte d'un problème, d'en changer si vous en avez besoin.

2voto

nullpointer Points 1135

Ce pseudo-code de la fonction:

not-void function-name () {
    do-something
    return value;
}

serait mieux utilisé lorsque la valeur renvoyée ne nécessite pas d'autres modifications sur elle. Le paramètre passé n'est modifié dans l' function-name. Il n'y a pas plus de références qu'il faut pour elle.


sinon identique, du pseudo-code de la fonction:

void function-name (not-void& arg) {
    do-something
    arg = value;
}

serait utile si nous avons une autre méthode de modération de la valeur de la même variable comme et nous avons besoin de conserver les modifications apportées à la variable de l'appel.

void another-function-name (not-void& arg) {
    do-something
    arg = value;
}

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