71 votes

Renvoyer une référence const à un objet au lieu d'une copie

En refacturant du code, je suis tombé sur des méthodes getter qui retournent un std :: string. Quelque chose comme ça par exemple:

 class foo
{
private:
    std::string name_;
public:
    std::string name()
    {
        return name_;
    }
};
 

Le getter aurait sûrement intérêt à retourner un const std::string& ? La méthode actuelle renvoie une copie moins efficace. Est-ce que retourner une référence const causerait des problèmes?

55voto

Dima Points 19888

Cela ne peut poser problème que si l'appelant stocke la référence plutôt que de copier la chaîne et essaie de l'utiliser après la destruction de l'objet. Comme ça:

 
foo *pFoo = new foo;
const std::string &myName = pFoo->getName();
delete pFoo;
cout << myName;  // error! dangling reference
 

Toutefois, étant donné que votre fonction existante renvoie une copie, vous ne perdriez aucun des codes existants.

30voto

Ogre Psalm33 Points 4886

En fait, un autre problème, plus précisément avec le retour d'une chaîne non par référence, c'est le fait qu' std::string permet d'accéder via le pointeur interne d' const char* via le c_str() méthode. Cela m'a causé de nombreuses heures de débogage des maux de tête. Par exemple, disons que je veux obtenir le nom de toto, et la transmettre à la JNI à être utilisé pour construire un jstring de passer en Java plus tard, et qu' name() est de retour une copie et non pas une référence. Je pourrais écrire quelque chose comme ceci:

foo myFoo = getFoo(); // Get the foo from somewhere.
const char* fooCName = foo.name().c_str(); // Woops!  foo.name() creates a temporary that's destructed as soon as this line executes!
jniEnv->NewStringUTF(fooCName);  // No good, fooCName was released when the temporary was deleted.

Si votre interlocuteur est d'aller faire ce genre de chose, il pourrait être préférable d'utiliser un certain type de pointeur intelligent, ou const référence, ou à tout le moins, ont une fâcheuse avertissement commentaire d'en-tête au-dessus de votre foo.nom() la méthode. Je mentionne JNI que les anciens Java programmeurs pourraient être particulièrement vulnérables à ce type de chaînage de méthode qui peut sembler contraire à couvert.

17voto

paercebal Points 38526

Un problème pour la const de référence de retour, si l'utilisateur codé quelque chose comme:

const std::string & str = myObject.getSomeString() ;

Avec un std::string retour, l'objet temporaire permettrait de rester en vie et se joint à la str jusqu'str est hors de portée.

Mais ce qui se passe avec un const std::string &? Ma conjecture est que nous aurions un const référence à un objet qui pourrait mourir lorsque son objet parent libère:

MyObject * myObject = new MyObject("My String") ;
const std::string & str = myObject->getSomeString() ;
delete myObject ;
// Use str... which references a destroyed object.

Donc ma préférence va à la const référence de retour (parce que, de toute façon, je suis plus à l'aise avec l'envoi d'une référence en espérant que le compilateur d'optimiser le supplément temporaire), tant que le contrat est respecté: "si vous le voulez, au-delà de mon objet de l'existence, ils le copier avant de mon objet de destruction"

10voto

rlerallut Points 2806

Certaines implémentations de std::string partager de la mémoire avec copie à l'écriture de la sémantique, donc retour par valeur peut être presque aussi efficace que le retour par référence et vous n'avez pas à vous soucier de la durée de vie des questions (le runtime le fait pour vous).

Si vous êtes inquiet au sujet de la performance, puis la comparer (<= ne peux pas souligner que suffisant) !!! Essayez les deux approches et de mesurer le gain (ou son absence). Si l'un est meilleur et vous vous souciez vraiment, puis l'utiliser. Si non, alors préférez en valeur pour la protection qu'il offre contre la durée de vie des questions mentionnées par d'autres personnes.

Vous savez ce qu'ils disent au sujet de faire des hypothèses...

7voto

Frank Points 16055

Ok, donc les différences entre le retour une copie et le retour de la référence sont:

  • Performance: le Retour de la référence peut ou ne peut pas être plus rapide; il dépend de la façon dont std::string est mis en œuvre par votre compilateur de mise en œuvre (comme d'autres l'ont souligné). Mais même si le retour à la référence de la mission après l'appel de fonction implique généralement une copie, en std::string name = obj.name();

  • Sécurité: le Retour de la référence peut ou ne peut pas causer des problèmes (bancales de référence). Si les utilisateurs de votre fonction ne sais pas ce qu'ils font, le stockage de la référence de la référence et de l'utiliser après la fourniture de l'objet est hors de portée alors il y a un problème.

Si vous le voulez, rapide et sécuritaire d'utiliser boost::shared_ptr. Votre objet en interne magasin de la chaîne en tant que shared_ptr et de retourner l' shared_ptr. De cette façon, il n'y aura pas de copie de l'objet va et et il est toujours plus sûr (à moins que vos utilisateurs tirez le pointeur brut avec get() et faire des trucs avec elle après que votre objet est hors de portée).

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