56 votes

C ++: la valeur renvoyée est-elle une valeur L?

Considérons ce code:

 struct foo
{
  int a;
};

foo q() { foo f; f.a =4; return f;}

int main()
{
  foo i;
  i.a = 5;
  q() = i;
}
 

Aucun compilateur ne s'en plaint, même Clang. Pourquoi la ligne q() = ... est-elle correcte?

56voto

Charles Bailey Points 244082

Non, la valeur de retour d'une fonction est une l-value si et seulement si elle est une référence en C++03). (5.2.2 [expr.appel] / 10)

Si le type retourné étaient un type de base alors ce serait une erreur de compilation. (5.17 [expr.cul] / 1)

La raison pour que cela fonctionne est que vous êtes autorisé à appeler des fonctions de membre (même les non-const fonctions membres) sur r-les valeurs de type de classe et la cession de l' foo est définie par l'implémentation de la fonction membre: foo& foo::operator=(const foo&). Les restrictions pour les opérateurs dans le paragraphe 5 ne s'appliquent à intégré dans les opérateurs, (5 [expr] / 3), si la résolution de surcharge sélectionne une fonction surchargée appel à un opérateur, alors la restriction pour que l'appel de fonction s'appliquent à la place.

C'est pourquoi il est parfois recommandé de retourner les objets de la classe type const objets (par exemple, const foo q();), cependant, cela peut avoir un impact négatif en C++0x où il peut inhiber la sémantique de déplacement de travailler comme ils le devraient.

8voto

Chad Points 7023

Parce que les structures peuvent être attribuées et votre q() renvoie une copie de l' struct foo de sorte que son affectation retournés struct à la valeur fournie.

Ce n'est pas vraiment n'importe quoi dans ce cas la pensée, car la structure est hors de portée par la suite et que vous ne gardez pas une référence, en premier lieu, donc on ne pouvait pas faire quelque chose avec elle de toute façon (dans le code).

Cela fait plus de sens (mais toujours pas vraiment une "meilleure pratique")

struct foo
{
  int a;
};

foo* q() { foo *f = new malloc(sizeof(foo)); f->a = 4; return f; }

int main()
{
  foo i;
  i.a = 5;

  //sets the contents of the newly created foo
  //to the contents of your i variable
  (*(q())) = i;
}

4voto

Tony D Points 43962

Une application intéressante de ceci:

 void f(const std::string& x);
std::string g() { return "<tag>"; }

...

f(g() += "</tag>");
 

Ici, g() += modifie le temporaire, ce qui peut être plus rapide que de créer un temporaire supplémentaire avec + car le segment de mémoire alloué pour la valeur de retour de g () peut déjà disposer de suffisamment de capacité disponible pour accueillir </tag> .

Maintenant, quel novice en informatique a dit quelque chose au sujet des optimisations et du mal ...? ; -].

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: