web-dev-qa-db-fra.com

Valeur de retour C ++, référence, référence const

Pouvez-vous m'expliquer la différence entre renvoyer une valeur, une référence à une valeur et une référence constante à une valeur?

Valeur:

Vector2D operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

Référence non const:

Vector2D& operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

Référence const:

const Vector2D& operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

Quel en est l'avantage? Je comprends le sens derrière la référence const passant à la fonction car vous voulez vous assurer de ne pas modifier cette valeur sur laquelle la référence pointe à l'intérieur d'une fonction. Mais je suis confus par le sens de renvoyer la référence const. Pourquoi le retour de référence est meilleur que le retour de valeur, et pourquoi le retour de référence const est meilleur que le retour de référence non-const?

37
Majak

Il n'y a pas de différence sauf si vous écrivez quelque chose de bizarre comme

(v1 += v2) = v3;

Dans le premier cas, l'affectation sera temporaire et l'effet global sera v1 += v2.

Dans le second cas, l'affectation sera à v1, donc l'effet global sera v1 = v3.

Dans le troisième cas, l'affectation ne sera pas autorisée. C'est probablement la meilleure option, car une telle bizarrerie est presque certainement une erreur.

Pourquoi le retour de référence est meilleur que le retour de valeur?

C'est potentiellement plus efficace: vous n'avez pas besoin de faire une copie de l'objet.

et pourquoi le retour de la référence const est meilleur que le retour de la référence non const?

Vous évitez les étrangetés comme dans l'exemple ci-dessus, tout en permettant des chaînages moins étranges comme

v1 = (v2 += v3);

Mais, comme indiqué dans les commentaires, cela signifie que votre type ne prend pas en charge les mêmes formes d'utilisation (ab) que les types intégrés, que certaines personnes considèrent souhaitables.

22
Mike Seymour

Valeur:

Renvoyer par valeur signifie que vous renvoyez une copie d'un objet. Cela impose des exigences à la classe (elle doit être copiable ou mobile). Cela signifie que pour un objet de certaines classes, le retour par valeur peut être coûteux (dans le cas où RVO ou NRVO ne fonctionne pas ou est désactivé). Cela signifie également que le nouvel objet est indépendant (sous réserve de sa conception) des autres objets et est une valeur qui lui est propre. C'est ce que vous devriez probablement retourner à partir de nombreux opérateurs binaires comme +, -, * et ainsi de suite.

Référence non const:

Vous retournez vraiment un alias pour un autre objet. L'alias étant non const vous permet de modifier un objet aliasé. C'est ce que vous devriez renvoyer de certains opérateurs unaires comme le préfixe ++ et -, et * (déréférence) car vous voulez généralement avoir la possibilité de modifier l'objet retourné.

Ceci est retourné par l'opérateur >> et l'opérateur << surchargés pour les flux. Cela permet de chaîner des opérateurs:

cout << 5 << "is greater then" << 1 << endl;
cin >> myInt >> myFloat;

Vous pouvez également renvoyer une référence à * this lorsque vous souhaitez autoriser le chaînage de méthodes régulières comme celle-ci:

object.run().printLastRunStatistics();

Référence const:

Comme ci-dessus mais vous NE POUVEZ PAS modifier un objet aliasé. Peut être utilisé au lieu de renvoyer par valeur lorsque l'objet à retourner est coûteux à copier et lorsque vous pouvez garantir son existence après le retour d'une fonction.

Voici ce que operator = renvoie généralement pour autoriser plusieurs affectations d'une manière que les types standard prennent en charge:

a = b = c;

Const-reference utilisé dans operator = empêche ce type d'utilisation (non pris en charge par le type standard pour autant que je m'en souvienne):

++(a = b);

qui serait autorisé si une référence normale était utilisée.

10
Tomek

La différence entre return-by-value et return-by-reference prend effet pendant l'exécution:

Lorsque vous renvoyez un objet par valeur, le constructeur de copie est appelé et une instance temporaire est créée sur la pile.

Lorsque vous renvoyez un objet par référence, tout ce qui précède n'a pas lieu, ce qui améliore les performances.


La différence entre return-by-reference et return-by-constant-reference n'a pas d'effet d'exécution et est simplement là pour vous protéger contre l'écriture de code erroné.

Par exemple, avec Vector2D& operator += (const Vector2D& vector), vous pouvez faire:

(x+=y)++ Ou (x+=y).func()func est une fonction non constante de la classe Vector2D.

Mais avec const Vector2D& operator += (const Vector2D& vector), le compilateur générera une erreur pour toute tentative similaire.

5
barak manos

C'est exactement la même chose que de passer un argument à la fonction.

Vous souhaitez renvoyer une référence const lorsque vous renvoyez une propriété d'un objet, que vous ne souhaitez pas modifier à l'extérieur de celui-ci. Par exemple: lorsque votre objet a un nom, vous pouvez faire la méthode suivante const std::string& get_name(){ return name; };. Quelle est la manière la plus optimale. Vous autorisez un accès "en lecture seule" à une propriété interne, sans copie au retour.

Lorsque vous surchargez des opérateurs, vous devez renvoyer un objet qui est modifiable, sinon une certaine syntaxe qui devrait normalement fonctionner produira des erreurs. C'est très important lorsque vous essayez un chaînage étrange.

Par exemple, l'option 3 ne fonctionnera pas avec quelque chose comme (v1 += v2).non_const_method(), Alors que ce qui suit:

v1+=v2;
v1.non_const_method();
5
luk32

Comme indiqué mais luk32 c'est juste pour s'assurer qu'aucune modification n'est autorisée aux objets retournés par cette fonction. Cela peut essentiellement vous aider à trouver vos erreurs logiques au moment de la compilation. Supposons que vous êtes sûr de ne pas changer un objet et que votre code change l'objet, il peut être suivi. Cela peut être considéré comme une bonne pratique de codage.

1
51k