2010-12-12 4 views
4

Je n'ai pas le sentiment (encore, j'espère) d'avoir choisi la sémantique de valeur ou de référence dans certaines situations. Y a-t-il une règle empirique que je peux appliquer?Valeur ou sémantique de référence dans cette situation?

Je choisis généralement des références pour tout autre type de données (char, int, bool, double, etc.). Cependant, il n'est parfois pas possible de renvoyer des références à partir d'une fonction, donc je devrais utiliser des pointeurs. La fonction suivante est un exemple:

Foo bar() 
{ 
    Foo f; 
    f.do_stuff(); 
    return f; 
} 

j'utiliser boost :: shared_ptr pour stocker l'objet Foo, mais il fait de travailler avec l'objet assez laid. Je suis actuellement en train de regarder une fonction qui retourne une deque qui n'aura presque jamais plus de 10 éléments (c'est ce que je suppose, je n'ai aucun moyen de m'en assurer). Serait-il correct de retourner ceci en valeur? Mes considérations sont-elles un cas d'optimisation prématurée?

+0

double possible de [Comment passer des objets à des fonctions en C++?] (Http://stackoverflow.com/questions/2139224/how-to-pass-objects-to-functions-in-c) – fredoverflow

Répondre

3

La valeur renvoyée est correcte, car la plupart des compilateurs optimisent la copie supplémentaire (c'est ce que l'on appelle l'optimisation de la valeur de retour, ou plutôt l'optimisation de la valeur de retour nommée dans votre cas).

Mais la façon dont idiomatiques est

void bar(Foo& out) 
{ 
    out.do_stuff(); 
} 
+2

@fhd: Il y a deux inconvénients avec cette approche: vous devez vous assurer que 'out' est dans l'état que vous voulez qu'il soit, et il est plus lourd à taper (et moins naturel). Je vais habituellement avec retour en valeur et compter sur le NRVO. –

+0

@fhd: Il y a cependant un avantage avec cette approche, c'est que vous ne construisez pas l'objet à l'intérieur de la fonction, donc vous vous débarrassez d'une éventuelle erreur de construction qui pourrait casser la sécurité des exceptions. –

+0

Cela semble raisonnable, merci! – Neo

3

Dans tous les cas, ne pas renvoyer tout ce qui est alloué sur la pile (c'est-à-dire la variable locale, comme ici) par référence ou pointeur.

+0

Pourquoi ? (limite de caractères ..) –

+1

@Alex: parce qu'il est alloué sur la pile alors quand la fonction renvoie cette variable basée sur la pile est libérée et votre pointeur ou référence devient invalide. – sashang

+0

@sashang: La formulation n'est pas claire (et même fausse). Cela devrait être "ne rien retourner ...". Je downvote, et j'annulerai le downvote fourni @Ofir édite sa réponse. –

0

Vous pouvez toujours le faire:

Foo& bar(Foo& f) 
{ 
    f.do_stuff(); 
    return f; 
} 

Et l'utiliser comme ceci:

Foo f; 
bar(f); 

L'inconvénient est que vous pouvez » t garantir que bar() recevra une nouvelle copie d'un objet Foo. Si cela est important, vous devrez le modifier à ceci:

Foo& bar(Foo& f) 
{ 
    f = Foo(); 
    f.do_stuff(); 
    return f; 
} 

Mais il y aura une initialisation inutile si elle ne reçoit une nouvelle copie. Alternativement, vous pouvez simplement examiner f avant doSomething() et lever une exception si ce n'est pas à la hauteur des attentes.

0

Utilisez une référence lorsque vous souhaitez conserver l'état d'une variable ou d'un objet (c.-à-d. Réacheminer la même variable vers la routine appelante après que la routine a appelé procesisng sur la variable/objet) et également en passant de grandes données à la fonction, il y aura une double copie des grandes données volumées.

Également dans certains cas où la copie d'objets par bit doit être empêchée, dans de tels cas, nous rendons le constructeur de copie d'une classe privé.

-1

Mes règles normales sont:

  1. utilisent toujours passer par valeur.

    Simple, hein? Référence sucer. Ils n'auraient jamais dû être introduits.

  2. Si vous avez une "valeur comme structure de données" passez-le. Si vous avez un "objet comme structure de données" passez un pointeur (sémantique de référence, passez par la valeur).

    Il est généralement clair quel genre de chose un type est: valeur ou objet. Si vous pouvez le muter, c'est un objet.

Questions connexes