2015-04-26 6 views
5

So che allontanare lo const -ness dovrebbe essere fatto con cura, e qualsiasi tentativo di rimuovere const -ness da un oggetto inizialmente const seguito dalla modifica dell'oggetto risulta in un comportamento non definito. Cosa succede se vogliamo rimuovere const -ness in modo che possiamo richiamare una funzione non const che non modifica l'oggetto? So che dovremmo effettivamente contrassegnare tale funzione const, ma supponiamo che io stia usando un codice "cattivo" che non ha la versione const disponibile.È sicuro rimuovere const tramite const_cast e richiamare una funzione non const che non modifica l'oggetto risultante?

Quindi, per riassumere, il codice è "sicuro"? La mia ipotesi è che finché non si finisce di modificare l'oggetto, si sta bene, ma non sono sicuro al 100%.

#include <iostream> 

struct Foo 
{ 
    void f() // doesn't modify the instance, although is not marked const 
    { 
     std::cout << "Foo::f()" << std::endl; 
    } 
}; 

int main() 
{ 
    const Foo foo; 
    const_cast<Foo&>(foo).f(); // is this safe? 
} 
+1

Indipendentemente dal fatto che sia consentito dallo standard, come già risposto, direi che non è né sicuro, né a posto. – hvd

+0

@hvd Perché un'operazione di sola lettura non è sicura? – Barry

+1

@Barry Non è questo il punto. Quella funzione membro può essere modificata in seguito, per invocare accidentalmente UB. – Columbo

risposta

3

comportamento indefinito rispetto const_cast è definito dalla norma del C++ 11 §3.8/9 (§3.8 è “ Object vita ”):

Creazione di un nuovo oggetto al posizione di archiviazione che occupa un oggetto const con durata di archiviazione statica, thread o automatica o, nella posizione di archiviazione che tale oggetto const utilizzato per occupare prima della sua durata, determina un comportamento non definito.

e §7.1.6.1/4 (§7.1.6.1 è “ I CV-qualificazioni ”)

Solo che ogni membro della classe dichiarata mutable (7.1.1) può essere modificato, qualsiasi tentativo di modificare un oggetto const durante la sua vita (3,8) si traduce in un comportamento indefinito.

In altre parole, si ottiene UB se si modifica un oggetto originariamente const, e altrimenti 1 non.

Lo stesso const_cast non introduce UB.


v'è inoltre una nota non normativa in §5.2.11/7 che “ seconda del tipo ” una scrittura attraverso il puntatore o riferimento ottenuto da un const_cast, può avere un comportamento indefinito.

Questa nota non-normativo è così lanoso che ha la sua nota non-normativo, che spiega che “ const_cast non si limita alle conversioni che gettano via un -qualifier const. ”.

Tuttavia, ancora con questo chiarimento non riesco a pensare a nessun caso in cui la scrittura potrebbe essere ben definita o meno a seconda del tipo, cioè non riesco a dare un senso a questa nota. Altre due risposte qui si concentrano sulla parola “ scrivendo ” in questa nota, e ciò è necessario per entrare in UB-land tramite §3.8/9, sì. L'aspetto per me piuttosto di pesce è il “ a seconda del tipo ”, che sembra essere la parte significativa di quella nota.


1) se non in quanto UB-regole per altre cose non const_cast -related entrare in gioco, ad esempio, annullamento di un puntatore che viene successivamente sottoposto a dereferenziazione in un contesto diverso da typeid -expression.

+0

C'è anche: 7.1.6.1 "Tranne che qualsiasi membro della classe dichiarato mutabile (7.1.1) può essere modificato, qualsiasi tentativo di modificare un oggetto const durante la sua vita (3.8) comporta un comportamento indefinito." –

+0

@CharlesBailey: Grazie, lo aggiungerò. Fatto. –

+0

"A seconda del tipo" ha senso se fa riferimento al tipo utilizzato durante la definizione dell'oggetto.Un qualificatore 'const' utilizzato nella definizione fa parte del tipo e se le modifiche sono consentite dipende dal fatto che sia stato utilizzato quel qualificatore. – hvd

6

Questo particolare esempio sembra essere sicuro (sono ben definiti comportamento) perché non c'è scrittura ad un oggetto che viene dichiarato const.

+0

finché non c'è "scrivi" è sicuro, giusto? È quello che pensavo. – vsoftco

+0

Esattamente, una scrittura avviene quando vengono scritti i byte che formano la rappresentazione dell'oggetto. –

6

Abbiamo questo in [dcl.type.cv]:

Solo che ogni membro della classe dichiarata mutable (7.1.1) può essere modificato, qualsiasi tentativo di modificare un oggetto const durante la sua vita (3.8) si traduce in un comportamento indefinito.

E c'è una nota (non-normativo) in [expr.const.cast] in cui si afferma:

[Nota: A seconda del tipo di oggetto, un'operazione di scrittura tramite il puntatore, lvalue o puntatore a membri dati risultanti da un const_cast che getta via un const-qualificazione può produrre indefinito comportamento (7.1.6.1). -end nota]

Un tentativo di modificare un oggetto o un'operazione di scrittura dopo un const_cast [può] causare un comportamento indefinito. Qui, non abbiamo un'operazione di scrittura.

Problemi correlati