2010-11-30 7 views
3

Selon ma compréhension, C++ ne vous permet pas de réinstaller une référence. En d'autres termes, vous ne pouvez pas modifier l'objet auquel une référence se réfère. C'est comme un pointeur constant à cet égard (par exemple int* const a = 3;).Exemple de code qui tente de réinstaller une référence de manière incorrecte

Dans certains code, je regardais aujourd'hui, je vu ce qui suit:

CMyObject& object = ObjectA().myObject(); 
// ... 
object = ObjectB().myObject(); 

immédiatement mes sonnette d'alarme se déclenche sur la dernière ligne de code ci-dessus. Le code n'essayait-il pas de réinstaller une référence? Pourtant, le code a été compilé.

Alors je compris que ce que le code a été fait invoquait simplement l'opérateur d'affectation (à savoir operator=) à réattribuer « objet interne à ObjectB » ObjectA objet interne. La référence object se référait toujours à ObjectA, c'est juste que le contenu de ObjectA correspondait maintenant à celui de ObjectB. Ma compréhension est que le compilateur générera toujours un opérateur d'assignation par défaut si vous n'en fournissez pas un, qui fait une copie superficielle (similaire au constructeur de copie par défaut). Comme une référence est typée (tout comme l'objet sous-jacent auquel elle fait référence), cela ne signifie-t-il pas que nous invoquerons toujours l'opérateur d'affectation lors de la réinstallation d'une référence, empêchant ainsi le compilateur de se plaindre de ce?

Je me suis creusé la tête en essayant de trouver une ligne de code illégale qui essaierait incorrectement de réinstaller une référence, pour que le compilateur se plaigne.

Quelqu'un peut-il me diriger vers un exemple d'un tel code?

Répondre

1

Je suis creusé la cervelle en essayant de trouver une ligne illégale de code qui va essayer de manière incorrecte à nouveau siège une référence, pour obtenir le compilateur de se plaindre.

const int i = 42; 
const int j = 1337; 

const int& r = i; 
r = j; 

Les non-initiés pourraient attendre la dernière ligne de re-siège r à j, mais au contraire, l'affectation à i échoue.

+0

Oui, c'est bon! Merci. – LeopardSkinPillBoxHat

2

Vous ne pouvez pas "réinsérer" une référence, car elle est syntaxiquement impossible. La variable de référence que vous utilisez et qui fait référence à l'objet utilise la même sémantique que si était une variable d'objet (non référence).

+0

Merci pour votre réponse. Donc, le langage ne vous laisse pas le faire. Pour une raison quelconque, j'étais sûr d'avoir déjà vu des erreurs de compilation à ce sujet. – LeopardSkinPillBoxHat

1

Vous ne pouvez pas écrire de code C++ portable pour réinsérer une référence ... le compilateur suit la référence et ne permet pas de la modifier. C'est une sorte d'alias pour tout ce à quoi il se réfère, et dans certains cas, la valeur de référence peut être incorporée directement dans le code au moment de la compilation. Dans certaines implémentations où une référence particulière se trouve stockée sous la forme d'un pointeur, et qui peut être consultée au moment de l'exécution, vous pouvez utiliser une conversion de réinterprétation pour l'écraser avec un pointeur vers un autre objet, mais le comportement est totalement indéfini et peu fiable. Pour peu qu'il vaut la peine (pratiquement rien, mais peut-être un smidge pour aider la compréhension de la mise en œuvre probable), qui pourrait ressembler à:

struct X 
{ 
    Y& y_; 
    X(Y& y) : y_(y) { } 
}; 

... 
X x(y1); 
*reinterpret_cast<Y**>(&x) = &y2; 
+0

@James: avoir du mal à suivre votre raisonnement là-bas. 'x' est un objet avec un membre' Y & ', qui, je l'espère, est représenté comme un pointeur' Y * 'à l'adresse' & x'. Le 'reinterpret_cast ' dit que je considère '& x' être un pointeur sur un pointeur vers' Y', alors je déférence que pour accéder au pointeur 'Y' (ie le pointeur au début de x), alors écraser avec un pointeur sur y2. Si j'ai fait une erreur, pouvez-vous la relier à la logique/aux étapes que j'exprime ici? Merci. –

+0

Excuses; J'ai mal lu le code. –

+0

@James: si vous allez mal interpréter le code, c'est le genre de slop qui le mérite ;-). À votre santé. –

1

Ma compréhension est que le compilateur toujours générer une affectation par défaut opérateur si vous n'en avez pas en fournir un, qui effectue une copie superficielle (similaire au constructeur par défaut ).

Comme une référence est typée (tout comme l'objet sous-jacent qu'il se réfère à), ne veut pas que cela signifie que nous allons toujours invoquer l'opérateur d'affectation lors d'une tentative de re-siège une référence , empêchant ainsi le compilateur de s'en plaindre?

Ce n'est pas tout à fait ça. La copie implicite (affectation) effectue une copie membre (pas nécessairement superficielle), et le compilateur ne laisse pas les choses implicites se produire implicitement aux membres de référence.

class X 
{ 
    int& ref; 
public: 
    X(int& r): ref(r) {} 
}; 

int main() 
{ 
    int i; 
    X a(i), b(i); 
    a = b; 
}