Quand à retourner un pointeur, scalaire et de 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 compile pas, parce que t
existe que dans le cadre de 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:
- Retourner un pointeur
- Retour 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
pour ê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;
}
Qui 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?
- "Je me déplace à partir de Java C++" ne signifie rien. Java n'est pas du C++. Java ne sera jamais en C++. La réflexion sur Java lors de la programmation C++ ne va pas vous aider à comprendre C++ ou vous aider à prendre les bonnes décisions. Aucune langue ne sera pas vous aider programme C++ à l'exception de C++, donc, oubliez vous connaissez d'autres langues, parce qu'ils ne sont pas en C++. Vous avez à apprendre le C++ si vous souhaitez programmer en C++, et ne pas essayer de transformer un langage préexistant en C++, parce que cela ne fonctionne pas seulement comme C++ c'est du C++. pourrais-je vous suggérer un bon livre?
- Une référence n'est pas proche de ce que Java n'. Le plus proche de la langue de construire à Java serait de retourner un pointeur. Mais qui ne prend pas en compte pour la gestion de la mémoire. Donc le plus proche de C++ construire pour Java serait de retourner un pointeur partagé. std::tr1::shared_ptr<T> (ou std::shared_ptr<T> ou boost::shared_ptr (en fonction de la version que vous utilisez)). Vous pouvez de nouveau et d'oublier à votre contenu de coeurs et généralement l'objet sera nettoyée correctement. Mais le C++ n'est pas Java. Vous avez besoin d'apprendre comment les utiliser correctement. N'apportez pas de Java, notions de C++ les langues sont simplement différentes.
- Ok, donc C++ n'est pas Java, mais en ignorant les spécificités de la langue. les idées exprimées dans le Java peut être traduite en C++. J'ai souvent programme dans un certain nombre de langues, souvent la syntaxe diffère, mais pas de la sémantique.
- ce n'est pas "nécessairement", et dans ce cas, il n'est pas juste de la sémantique. "Idées" est un terme générique, votre argument n'est ni falsifiable ou significatives. C++ et Java sont des langues différentes, et vous faites les choses de différentes manières. Les "idées" qui correspondent à des règles de base comme l'exécution d'instructions, et rien vous dire sur les choix de conception.
- C'est une idée fausse.
- À l'aide de "Analyse Comparative" est très humaine et très fréquent. J'ai trouvé que c'était un excellent outil pour aider à enseigner aux gens. Je ne comprendrai jamais le "suivre le troupeau, fermé d'esprit" approche.
- Vous n'avez pas à vérifier le retour de
new
NULL ounullptr
.new
est garanti pour lever une exception sur l'échec d'allocation.
Vous devez vous connecter pour publier un commentaire.
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.
A a = B->GetA()
oùB::GetA
est déclarée commeconst A& B::GetA()
ou même sans const, va provoquer une copie.Tout simplement, éviter d'utiliser des pointeurs et l'allocation dynamique par
new
dans la mesure du possible. Utiliser des valeurs, des références et automatiquement les objets alloués à la place. Bien sûr, vous ne pouvez pas toujours éviter l'allocation dynamique, mais il devrait être un dernier recours, et non en premier.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 (souvent
::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 à partir de Java est que
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.
const
aura une définition plus stricte, car l'état de l'objet peut être dans la mémoire qui est en fait non-inscriptible.mutable
.Retour par valeur est une chose courante pratiquée en C++. Toutefois, lorsque vous êtes de passage à un objet, vous passez par référence.
Exemple
Ci-dessus est un simple exemple de passage d'un objet par référence. En réalité, vous auriez une méthode appelée isTraderAllowed pour les actions de classe, mais je vous montrais une utilisation réelle de passage par référence.
Un point concernant la transmission par valeur ou par référence à:
Compte tenu des optimisations, en supposant une fonction est 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:
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.