Que doit faire un C++ getter retour
Quelle est la meilleure pratique pour un C++ méthode de lecture qui est censé renvoyer un non trivial type, mais un membre qui est de type classe ou structure.
- Retour par valeur, tels que:
MyType MyClass::getMyType() { return mMyType; }
- Retour par référence const:
const MyType& MyClass::getMyType() { return mMyType; }
- Retour par adresse:
MyType* MyClass::getMyType() { return &mMyType; }
où
class MyType { /* ... */ };
class MyClass
{
private:
MyType mMyType;
}
J'ai particulièrement s'inquiéter de la suite des usages de cette méthode. Pouvez-vous veuillez donner des précisions dans les détails de la façon dont cela peut affecter la copie de l'objet, et le danger de dangling références et sauvage disparu des pointeurs si function()
veut l'enregistrer pour une utilisation ultérieure.
MyType* savedPointer;
SomeType function(MyType* pointer) { savedPointer = pointer; };
un. valable pour 1. et 2.
{
MyType t = myClass.getMyType();
function(&t);
}
//is savedPointer still valid here?
b. valable pour 1. et 2.
{
const MyType& t = myClass.getMyType();
function(&t);
}
//is savedPointer still valid here?
c. valable pour 1. et 2.
{
MyType& t = myClass.getMyType();
function(&t);
}
//is savedPointer still valid here?
d. valable pour 3.
{
MyType* t = myClass.getMyType();
function(t);
}
//is savedPointer still valid here?
où myClass
est un objet de type MyClass
.
- Il dépend du contexte. Voulez-vous voir les modifications à l'intérieur de la classe (par exemple, modifier un élément du vecteur) ou voulez-vous exlicitely seulement la valeur, mais jamais(!) avez des modifications à l'original? À mon avis, le pointeur ne doit pas être utilisé en général. Les types de conteneurs devrait retourner par ref ou const ref et le reste par la valeur (ou même pas de lecture du tout!). Le point de classes encapsulation des données (entre autres fonctions). Revenant toujours par des non-const de référence serait ridicule.
- Vous pouvez également retourner les pointeurs intelligents, qui permettent d'économiser que vous beaucoup de s'inquiéter...
- Vous ne pouvez pas retourner un pointeur intelligent ici. Il n'est pas alloué dynamiquement un objet (on ne devrait pas l'être).
- d'accord, de renvoyer un pointeur intelligent de la variable d'instance doit être un pointeur intelligent, c'est ce que je voulais dire
- Mais pourquoi voudriez-vous faire de la variable d'instance un pointeur intelligent?
- bien il existe de nombreuses situations où il est justifié, peut-être pas ici, mais compte tenu de l'OP était inquiet de la mise en danger de dangling références et sauvage disparu pointeurs, j'ai pensé à mentionner des pointeurs intelligents serait adéquat.
- Il y a très, très peu de situations où une smart pointeur de membre est justifiée (sauf peut-être
unique_ptr
, mais dans ce cas, vous ne voulez pas retourner une "copie" de launique_ptr
). - laissez-nous continuer cette discussion dans le chat
- Il n'y a pas "doit" répondre à votre question. Cela dépend de votre intention, le niveau d'accès vousune re prêts à fournir et combien détails d'implémentation, vous êtes prêt à exposer. Voir ici pour une réponse plus détaillée: stackoverflow.com/a/2977172/187690
Vous devez vous connecter pour publier un commentaire.
Vous pouvez fournir à la fois const et non const versions:
Je n'aurais pas fournir un pointeur version, car cela implique que la valeur de retour peut être le pointeur null, ce qui ne peut jamais être dans ce cas.
Le point réel, cependant, est que vous êtes essentiellement donné à l'appelant un accès direct à l'objet interne. Si c'est votre intention, alors vous pourriez aussi bien faire le membre de données publiques. Si elle ne l'est pas, alors vous aurez besoin de travailler plus fort pour cacher l'objet.
Une option est de conserver la
MyType const &
accesseur, mais de fournir plus de moyens indirects pour modifier l'objet interne (setMyType(…)
ou quelque chose de plus adapté à la sémantique de ce que vous essayez d'exprimer au niveau de la classe conteneur).public
membre à ce point.MyType&
la modification de la mise en œuvre ultérieure est à peu près impossible sans rupture de l'ABI.MyClass
, ou un allouée dynamiquement instance (qui peuvent être créés sur demande), ou d'un fil instance spécifique etc.pair
juste a le public et les membres, car il n'y a pas d'invariants.vector
d'autre part, a un certain nombre de getters et setters, car il doit gérer sa taille, la capacité, le pointeur vers le début, etc. @Jean pourquoi avez-vous besoin d'un point d'arrêt sur l'accès? Cela ressemble à ce que vous voulez vraiment est un point de rupture, que vous n'avez pas besoin d'un accesseur pour.En général, vous devriez préférer retourner à la valeur, à moins que vous
explicitement voulez garantir que la référence désigne
un membre (qui expose une partie de votre mise en œuvre, mais est
souhaitable dans les cas comme
std::vector<>::operator[]
). De retourune référence empêche les variations ultérieures de la classe, puisqu'il signifie que
vous ne pouvez pas retourner une valeur calculée. (Cela est particulièrement
important si la classe est une classe de base, depuis
renvoie une référence crée cette restriction pour tous les dérivés
les classes.)
Le seul moment où vous devriez retourner par pointeur est si une recherche ou
quelque chose est en cause, ce qui peut en retour en retour
un pointeur null.
Renvoie une référence à const peut être une optimisation valide, si
le générateur de profils indique des problèmes de performance ici, et l'appel
le site peut également traiter avec un const référence (pas de modification de
la valeur retournée, pas de problèmes avec la durée de vie de l'objet). Il
doit être pesé en fonction des contraintes supplémentaires sur la
la mise en œuvre, bien sûr, mais dans certains cas, il est justifié.
Je serais toujours retourner une référence const. Si vous avez besoin de modifier la valeur, il est de retour il suffit d'utiliser une fonction de définition.
Retour par valeur, tels que:
MyType MyClass::getMyType() { return mMyType; }
doit être évitée, car vous copiez le contenu de votre objet. Je ne vois pas le gain pourrait avoir, mais je vois les inconvénients sur la performance.Retour par référence const:
const MyType& MyClass::getMyType() { return mMyType; }
est plus généralement utilisé de cette façon:Toujours la version const. Le non-const version est facultatif, car cela signifie que quelqu'un pouvez modifier vos données. C'est ce que je voudrais vous encourager à utiliser.
Retour par adresse:
MyType* MyClass::getMyType() { return &mMyType; }
est surtout utilisé lorsque les données sont en option. Elle doit souvent être vérifiées avant d'être utilisées.Maintenant, votre cas d'utilisation, je conseil vivement de ne pas garder un pointeur enregistrer pour plus d'un champ. J'ai peut souvent conduire à l'appropriation des problèmes. Je que vous avez à faire, prendre un coup d'oeil à shared_ptr.
Pour vos exemples, il y a deux cas:
un. savedPointer ne sera plus valide après l'accolade fermante.
b,c, et d de. savedPointer est valable qu'après l'accolade fermante, mais attention, il ne devrait pas survivre à
myClass
.a)
MyType t =
va créer une copie de l'objet 1 et 2. Enregistré pointeur ne sera pas valide une fois que t est hors de portée.b) enregistrées pointeur sera valable pour le cas de retourner une référence, mais pas pour les cas de renvoi d'un objet. Pour la référence, la durée de vie du pointeur serait le même que maclasse. De cours &t sur un const réf serait un const t* pas un t* et donc de ne pas en fonte dans votre appel à
function(MyType*)
.c) Même que b, si le code n'est pas valide pour les 2 parce que vous ne pouvez pas jeter un
const MyType&
à unMyType&
. En général, ce serait une mauvaise pratique et la const forme serait plus acceptable.d) savedPointer aura la même durée de vie que maclasse.
Je préfère généralement se pencher vers retourner une référence ou un const de référence en fonction de ce que vous pensez être en mesure de le faire avec la valeur de retour. Si vous revenez d'une référence (non-const), vous pouvez faire des choses comme:
myClass.getMyType() = ...
, tandis que si vous retournez un const référence, l'objet est en lecture seule.