2011-11-23 5 views
18

Vorrei verificare la mia comprensione e le conclusioni su questo argomento.Ho ragione nel dire che const_cast seguito da modifiche su un ref-to-const legato a un temporaneo va bene?


Su IRC, è stato chiesto:

È accettabile const_cast un riferimento const che è destinato a un oggetto temporaneo?

Traducendo: ha un const ref-a-legato ad un temporaneo e vuole gettare via la sua const -ness per modificarlo.

La mia risposta è stata che avevo chiesto a similar question in precedenza, in cui il consenso sembra essere che provvisori stessi non sono intrinsecamente const, e quindi che si può lanciare al largo della const -ness di un riferimento si deve a loro, e modificare loro attraverso il risultato. E, a condizione che esista ancora il riferimento originale a const, ciò non influirà sulla durata del temporaneo.

Cioè:

int main() 
{ 
    const int& x = int(3); 

    int& y = const_cast<int&>(x); 
    y = 4; 

    cout << x; 
} 
// Output: 4 
//^Legal and safe 

ho ragione?


(Naturalmente, se tale codice è in realtà consigliabile è tutta un'altra cosa!)

+0

@ Mark: Oh, un letterale potrebbe essere una cattiva scelta. Ora l'ho reso un non-letterale per questa domanda. –

+0

Stavo per dire che non c'erano temporaries in quel codice. Fortunatamente, ho aggiornato la pagina prima di farlo :) – Gorpik

+0

afaik (ma non riesco a trovarlo nello stadnard) dice qualcosa come "quando è stato dichiarato come const, quindi non si può castare la costanza" ... quindi la domanda è , è un letterale dichiarato come const? Non lo penso, dal momento che risulta in un oggetto temporaneo, quindi è dichiarato come const? Non ne ho idea, ma le mie budella dicono: no – PlasmaHH

risposta

8

No.

In primo luogo, per quanto posso dire, sia che si tratti è un letterale o non è irrilevante. Rvalues ​​di tipo non-classe hanno sempre non-cv qualificato tipi (§3.10/9), tuttavia, in §8.5.3 (inizializzazione di riferimento), si avere:

Un riferimento al tipo “ CV1 T1” viene inizializzato da un'espressione del tipo ‘cv2 T2’ come segue:

[...]

-

Altrimenti, una temporanea di tipo ‘CV1 T1’ viene creata e inizializzata dall'espressione di inizializzazione utilizzando le regole per un init di copia non di riferimento ializzazione (8.5). Il riferimento è quindi legato al temporaneo. Se T1 è riferito a T2, cv1 deve essere la stessa qualifica di cv, o maggiore riqualificazione di, cv2; altrimenti, il programma è mal formato.

(. Tutti i punti precedenti riguardano sia lvalue o tipi di classe)

Nel nostro caso, abbiamo:

int const& x = ...; 

Così cv1 T1 è int const, e l'oggetto temporaneo creiamo ha tipo int const.Questo è un const di livello superiore (sull'oggetto), quindi qualsiasi tentativo di modificarlo è non definito.

Almeno, questa è la mia interpretazione. Vorrei che lo standard fosse un po 'più chiaro a riguardo.

+0

Questo non rende semplicemente contraddittorie 3.10/9 e 8.5.3? –

+2

@ TomalakGeret'kal Non proprio. §3.10/9 parla di rvalues ​​e lvalue. Un'espressione come '3' o' int (3) 'è un valore. §8.5.3 spiega come inizializzare un riferimento; i riferimenti non sono mai valori validi e devono riferire a un oggetto. Quindi, §8.5.3 dice che il compilatore crea un oggetto temporaneo , inizializzato con il valore rval, e lega il riferimento a questo. Non si ottiene un riferimento a un valore letterale intero, perché tali elementi non esistono; si ottiene un riferimento a un oggetto senza nome altrimenti invisibile, che ha il tipo di riferimento (e non dell'inizializzatore ). –

+0

Ah! Vedo ................. Interessante. Allora sono d'accordo con la tua conclusione, e suppongo che ciò significhi che estendere la durata dei temporari ha lo sfortunato corollario che non possiamo modificarli. –

1

La risposta dipende da come viene creato il temporaneo e da come viene inizializzato il riferimento.

Se si creava in modo esplicito il temporaneo come oggetto di tipo non const e la situazione garantisce che il riferimento const sia collegato in modo specifico al temporaneo che è stato creato, allora si può tranquillamente scartare la costanza del riferimento e modificare l'oggetto.

D'altra parte, se il temporaneo è stato creato implicitamente per te dal compilatore, il temporaneo stesso sarà const. In tal caso, modifica quella porta temporanea a UB.

Sfortunatamente, lo standard di linguaggio C++ da solo sembra non garantire alcuna situazione in cui il primo approccio di inizializzazione è necessariamente preso. In ogni contesto il compilatore può introdurre una copia temporanea aggiuntiva del tuo originale temporaneo. Il nuovo temporaneo sarà const (come detto sopra) e quindi non modificabile. Se ciò accada o no è definito dall'implementazione, come indicato in 8.5.3/5.

Quindi, in generale, la risposta è no, mentre una risposta specifica per l'implementazione potrebbe essere diversa.

+0

Non riesco a trovare nulla in 8.5.3/5 che indica che qualsiasi temporaneo sul RHS non andrebbe a cadere nella clausola citata da James. Puoi dimostrare che lo scenario è diverso quando "creo esplicitamente il [me] temporaneo"? –

+1

@Tomalak Geret'kal: beh, per un tipo di classe 'T', se faccio solo' const T & r = T() ', ho la possibilità che il riferimento venga collegato direttamente al mio' T() '(dice 8.5.3/5), che non è const. In tal caso è perfettamente legale gettare via la costanza e modificare l'oggetto. – AnT

+0

8.5.3/5 è enorme e, come ho detto, non riesco a trovare i passaggi deduttivi che stai utilizzando. –

Problemi correlati