33 votes

Quand retourner un pointeur, un scalaire et une référence en C ++?

Je me déplace à partir de Java-C++ et je suis un peu confus de la langue de la flexibilité. Un point est qu'il existe trois façons de stocker des objets: Un pointeur, une référence et un scalaire (stockage de l'objet lui-même, si je comprends bien).

J'ai tendance à utiliser des références si possible, parce que c'est proche de Java que possible. Dans certains cas, par exemple, des getters pour les dérivés attributs, ce n'est pas possible:

MyType &MyClass::getSomeAttribute() {
    MyType t;
    return t;
}

Cela ne veut pas compiler, car t il n'existe que dans le champ d'application de l' getSomeAttribute() et si je retourne une référence à elle, elle aurait point de nulle part avant que le client puisse l'utiliser.

Donc je suis parti avec deux options:

  1. Retourner un pointeur
  2. De retour d'un scalaire

Retournant un pointeur devrait ressembler à ceci:

MyType *MyClass::getSomeAttribute() {
    MyType *t = new MyType;
    return t;
}

Ce serais de travail, mais le client devra vérifier ce pointeur pour NULL afin d'être vraiment sûr, quelque chose qui n'est pas nécessaire avec les références. Un autre problème est que l'appelant aurait assurez-vous que t est libéré, je préfère ne pas traiter que si je peux l'éviter.

L'alternative serait de revenir à l'objet lui-même (scalaire):

MyType MyClass::getSomeAttribute() {
    MyType t;
    return t;
}

C'est assez simple et tout ce que je veux dans ce cas: Il se sent comme une référence et il ne peut pas être null. Si l'objet est hors de portée dans le code du client, il est supprimé. Assez pratique. Cependant, j'ai rarement vu quelqu'un le faire, est-il une raison pour que? Est-il une sorte de problème de performance si je retourne un scalaire au lieu d'un pointeur ou une référence?

Ce qui est le plus commun/approche élégante pour gérer ce problème?

24voto

jalf Points 142628

Retour par valeur. Le compilateur peut optimiser loin de la copie, de sorte que le résultat final est ce que vous voulez. Un objet est créé, et est retourné à l'appelant.

Je pense que la raison pour laquelle il est rare de voir des gens faire c'est parce que vous êtes en train de regarder le mauvais code C++. ;) La plupart des gens venant de Java se sentir mal à l'aise de faire quelque chose comme cela, alors ils l'appellent new tous sur la place. Et puis ils obtiennent des fuites de mémoire dans tous les sens, avez pour vérifier la valeur NULL et tous les autres problèmes qui peuvent causer. :)

Il pourrait également être intéressant de souligner que le C++ références ont très peu en commun avec Java références. Une référence en Java est beaucoup plus semblable à un pointeur (il peut être réinstaller, ou la valeur NULL). En fait, la seule véritable différence est que l'un pointeur peut pointer vers une valeur d'ordures (s'il est non initialisée, ou qu'il pointe vers un objet qui a disparu hors de portée), et que vous pouvez faire de l'arithmétique de pointeur sur un pointeur sur un tableau. C++ référence est un alias pour un objet. Une Java de référence ne se comportent pas comme ça.

2voto

Omnifarious Points 25666

Retour par valeur peut introduire des pénalités parce que cela signifie que l'objet doit être copié. Si c'est un objet de grande taille, comme une liste, qui peut être très coûteux.

Mais les compilateurs modernes sont très bien faire cela se produise pas. Les normes C++ dispose expressément que le compilateur est autorisé à éluder les copies dans certaines circonstances. L'instance particulière qui seraient pertinentes dans le code de l'exemple que vous avez donné est appelée la "valeur de retour optimisation".

Personnellement, je suis de retour par (habituellement const) référence quand je suis de retour d'un membre de la variable, et revenir à une sorte de pointeur intelligent objet quelconque (fréquemment ::std::auto_ptr) quand j'ai besoin d'allouer dynamiquement de quelque chose. Sinon, j'retour par valeur.

J'ai aussi très souvent const des paramètres de référence, et cela est très fréquent en C++. C'est une façon de passer d'un paramètre et en disant: "la fonction n'est pas autorisé à toucher ce". Fondamentalement, un paramètre en lecture seule. Il ne doit être utilisée que pour les objets qui sont plus complexes que d'un nombre entier ou un pointeur si.

Je pense qu'un grand changement de Java est qu' const est important et très souvent utilisé. Apprenez à le comprendre et en faire votre ami.

Je pense aussi que Neil réponse est bonne, en déclarant que le fait d'éviter l'allocation dynamique chaque fois que cela est possible est une bonne idée. Vous ne devriez pas se contorsionner votre conception trop de choses à faire qui se produisent, mais vous devriez certainement préfèrent les choix de conception dans lequel il ne doit pas se produire.

0voto

user373215 Points 561

Le retour par valeur est une chose courante pratiquée en C ++. Cependant, lorsque vous passez un objet, vous passez par référence.

Exemple

  main()
   {

       equity trader;

       isTraderAllowed(trader);

       ....
    }

    bool isTraderAllowed(const equity& trdobj)
    {
             ... // Perform your function routine here.
    }
 

Ce qui précède est un exemple simple de passage d'un objet par référence. En réalité, vous auriez une méthode appelée isTraderAllowed pour l'équité de classe, mais je vous montrais une réelle utilisation du passage par référence.

0voto

Pooria Points 864

Un point concernant la transmission par valeur ou par référence:
Compte tenu des optimisations, en supposant une fonction inline, si son paramètre est déclaré "const Type de données objectName" que de Type de données pourrait être n'importe quoi, même des primitives, pas de copie d'objet seront impliquées; et si son paramètre est déclaré "const Type & objectName" ou "Type de données & objectName" que le nouveau Type de données pourrait être n'importe quoi, même des primitives, pas d'adresse de les prendre ou de pointeur seront impliqués. Dans les deux cas précédents arguments d'entrée sont utilisés directement dans le code assembleur.

Un point sur les références:
Une référence n'est pas toujours un pointeur, comme exemple quand vous avez le code suivant dans le corps d'une fonction, la référence n'est pas un pointeur:

int adad=5;
int & reference=adad;  

Un point au sujet de son retour par valeur:
comme certaines personnes l'ont mentionné, en utilisant les bons compilateurs avec une capacité d'optimisations, retour par tout type de valeur ne sera pas provoquer une copie supplémentaire.

Un point au sujet de son retour par la référence:
En cas de inline fonctions et optimisations, le retour par référence n'impliquera pas l'adresse de la prise ou du pointeur.

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