2011-09-07 18 views
5

Dire l'oggetto èquindi qual è il tipo di "questo"? Perché "questo" non è un lvalue?

class A { 
public : void Silly(){ 
    this = 0x12341234; 
} 

lo so mi metterò errore del compilatore ' 'questo' non è un lvalue.' Ma non è neanche temporaneo. Quindi qual è l'ipotetica dichiarazione di "questo"?

Compilatore: compilatore GCC 4.2 su mac.

+4

Obbligatorio 'try {this = follia; } catch (...) {this = sparta; } ' – corsiKa

+0

Fuori interesse, quale compilatore ti dà questo messaggio? –

+0

@Oli: se il codice viene modificato in 'this = (A *) 0x12341234;', i report VC++ "* l'operando di sinistra deve essere l-value *" - un tipo di simile. – ildjarn

risposta

6

Per alcuni di classe X, this ha il tipo X* this;, ma non ti è permesso di assegnare ad esso, quindi, anche se in realtà non hanno il tipo di X *const this, agisce quasi come se fosse stato per quanto riguarda la prevenzione assegnazione va. Ufficialmente, è un prvalue, che è la stessa categoria di qualcosa come un intero letterale, quindi provare ad assegnarlo è approssimativamente equivalente a provare ad assegnare un valore diverso a 'a' o 10.

Si noti che in primi C++, this era un lvalue - assegnando ad this è stato permesso - avete fatto che per gestire l'allocazione di memoria per un oggetto, vagamente simile a un sovraccarico new e delete per la classe (che wasn 't supportato ancora in quel momento).

+0

OK, capito. Ho cancellato il mio commento inutile. – AnT

3

Per prima cosa, this non è una variabile: è una parola chiave. Se utilizzato come valore di rvalue, il suo tipo è A * o A const *. Nel moderno C++, l'assegnazione a this è proibita. Non è possibile prendere l'indirizzo di this. In altre parole, non è un valore valido.

+2

"* Se usato come valore di rvalue, il suo tipo è' A * 'o' A * const'. * "Si intende' A * 'o' A const * '. – ildjarn

+0

Giusto. Dannazione per la costanza del puntatore. –

+2

@ Seva: C'è una semplice regola che aiuta a mantenere chiaro. Se si guarda una dichiarazione come "T * p;", "T" è il tipo di destinazione e "p" è il nome del puntatore stesso, con "*" come tipo di "muro" tra i due. Se metti 'const' (o' volatile') sul lato del puntatore del muro, questo influenza il puntatore. Se lo metti sul lato "tipo" del muro, influisce sul tipo a cui punta il puntatore. –

1

Si ottiene un errore del compilatore perché this è un puntatore const sull'istanza della classe dello stesso tipo di quella classe. Non è possibile assegnarlo anche se è possibile utilizzarlo per modificare altri membri della classe in metodi qualificati non-const, metodi di chiamata e operatori. Nota anche perché è un'istanza che i metodi statici non hanno un puntatore this.

ipotetico:

class Whatever 
{ 
    // your error because this is Whatever* const this; 
    void DoWhatever(const Whatever& obj) { this = &obj; } 

    // this is ok 
    void DoWhatever(const Whatever& obj) { *this = obj; } 

    // error because this is now: const Whatever* const this; 
    void DoWhatever(const Whatever& obj) const { *this = obj; } 

    // error because this doesn't exist in this scope 
    static void DoWhatever(const Whatever& obj) { *this = obj; } 
}; 
4

E 'impossibile fornire una "dichiarazione" per this. Non c'è modo di "dichiarare" un valore in C++. E this è un valore, come già sapete.

La frequenza insufficiente e la rvalueness sono le proprietà delle espressioni che producono questi valori, non le proprietà di dichiarazioni o oggetti. A tale riguardo, si può persino sostenere che è impossibile dichiarare un lvalue. Tu dichiari un oggetto. Lvalue è ciò che viene prodotto quando si utilizza il nome di quell'oggetto come espressione. In questo senso sia "per dichiarare un valore nominale" che "per dichiarare un valore" sono espressioni di ossimoro.

La tua domanda sembra anche suggerire che le proprietà di "essere un lvalue" e "essere un temporaneo" siano in qualche modo complementari, cioè tutto è presumibilmente un lvalue o un temporaneo. In realtà, la proprietà di "essere un temporaneo" non ha alcun business qui. Tutte le espressioni sono o lvalue o rvalue. E this sembra essere un valore.

I temporanei, al contrario, possono essere percepiti come rvalori o come valori l, a seconda di come si accede al temporaneo.

P.S. Nota, BTW, che in C++ (al contrario di C) le funzioni ordinarie sono lvalue.

+0

Bene, provenendo da sfondo C tendo a vedere la dichiarazione di rvalue come "const lvalue-type" –

+0

@Ajeet: È davvero strano. Il linguaggio C non è molto diverso dal C++ in questo senso. In linguaggio C la dichiarazione 'const int' dichiara un ** lvalue **, non un valore. – AnT

+0

Sebbene non sia possibile dichiarare un valore rval, è possibile (ad esempio) dichiarare/definire un lvalue di un tipo a cui tale valore può essere assegnato senza una conversione. –

2

Per rispondere alla seconda parte, "perché non è un lvalue this", sto speculando da motivazione reale della commissione, ma i vantaggi sono:

  1. assegnando a this non ha molto senso logico quindi non è necessario che appaia sul lato sinistro dei compiti. Rendendolo un valore importante sottolinea che ciò non ha molto senso vietandolo e significa che lo standard non deve definire cosa succede se lo si fa.
  2. rendendolo un rvalue ti impedisce di puntare ad esso, che a sua volta elimina l'implementazione di qualsiasi necessità di fornirlo con un indirizzo, proprio come una variabile automatica modificata da register. Ad esempio, potrebbe assegnare un registro in funzioni membro non statiche per memorizzare this. Se si prende un riferimento const, quindi a meno che l'uso non consenta l'ottimizzazione astuta, è necessario copiarlo da qualche parte con un indirizzo, ma almeno non deve essere lo stesso indirizzo se lo si fa due volte in rapida successione, poiché sarebbe necessario be if this erano una variabile dichiarata.
+0

Per vedere la dimostrazione nel budino, stavo giocando con questo: const int i = 10; * (int *) ((void *) & i) = 20; Che è valido Ma non posso farlo con "questo" perché non posso applicare e "questo". –

+1

Sì, anche se IIRC lo standard in realtà non definisce "programma valido" o "codice valido". Il tuo codice è ben formato ma ha un comportamento indefinito, alcune persone sembrano chiamarlo "non valido". Il tuo punto è, tuttavia: è una cosa stupida che puoi fare con un valore costante, ma non può farlo con un valore. Un trucco simile che funziona con 'this' è' template T & stupid (const T & r) {return const_cast (r);} 'seguito da' stupid (this) = 0; '. Non consigliato. –

+0

+1 Hmm, quindi i modelli sono qualcosa che non è ancora stato reso infallibile quindi. :) –