2010-04-20 16 views
36

Come regola generale, è molto spesso considerato una cattiva pratica utilizzare const_cast<>() in codice C++ poiché rivela (il più delle volte) un difetto nella progettazione.Uso corretto (s) di const_cast <>

Mentre Sono totalmente d'accordo con questo, io però chiedo che cosa sono i casi sono state utilizzando const_cast<>() è ok e l'unica soluzione .

Potresti, per favore, darmi qualche esempio che conosci/hai incontrato?

Grazie mille.

risposta

16

const_cast è usato anche per rimuovere volatile modificatori, come messo in pratica in questo (controversed) articolo:

http://www.drdobbs.com/184403766

+0

Ho appena imparato qualcosa di fantastico! Grazie mille ! – ereOn

+0

anch'io, +1, grazie! – Sanish

25

è praticamente progettato per essere utilizzato solo con le API legacy che non sono const corretta vale a dire con una funzione non è possibile modificare che ha un'interfaccia non const, ma in realtà non mutano niente sull'interfaccia

0

Sì ovviamente, quando il tuo codice chiamante che non puoi modificare e non è const corretto. Va notato che dovresti usarlo solo con chiamate a funzioni che sai per certo non modificheranno i tuoi dati!

10

Sono d'accordo con la tua affermazione che il suo uso normale è perché è necessario nascondere un 'difetto di progettazione'.

IME uno degli scenari di utilizzo tipici è quando si tenta di interfacciare C++ al codice C esistente. Un sacco di codice C esistente prende le stringhe C come char * anche quando la stringa non viene modificata mentre solitamente vengono rappresentate come qualcosa che viene convertito in un const char * in C++. Questo è un disadattamento di impedenza tra le due lingue che normalmente si risolvono usando un const_cast. Naturalmente è meglio essere molto assicurarsi che il codice si sta interfacciamento con non ottiene tutte le idee carino sulla modifica dei dati che viene passata in.

Direi che si tratta di un codice di odori in appena scritto codice, ma per interfacciarsi con il vecchio codice C e C++, è un male necessario. Detto questo, sarei estremamente diffidente nei confronti del codice che richiede const_cast per tutti gli oggetti non POD in quanto è normalmente un problema che dovrebbe essere risolto a livello di progettazione e non a livello di codice.

2

Un uso molto legittima di questo è quando si ha sia un const e api non const (per const e non const oggetti rispettivamente) come in

class Bar { 
    const SomeType& foo() const; 
    SomeType& foo(); 
} 

Poi dal momento che non vogliamo duplicare il codice in entrambe le funzioni che usiamo spesso

class Bar { 
    SomeType& foo() { 
     //Actual implementation 
    } 
    const SomeType& foo() const { 
     return const_cast<Bar*>(this)->foo(); 
    } 
}; 

Questo è, naturalmente partendo dal presupposto che pippo non fare qualcosa che viola la semantica const.

+2

Bisogna che all'indietro e può portare a comportamenti non definiti. – GManNickG

+0

cura di elaborare? – Jasmeet

+3

La preoccupazione è che la versione non-const di 'foo' possa modificare' this', e quindi è "non sicuro" chiamarla su un oggetto const che hai lanciato su non-const. È "sicuro" chiamare una funzione membro const su un oggetto non const, quindi è preferibile la versione di GMan. Tuttavia, la versione di GMan può anche portare a un comportamento indefinito quando il client modifica il valore restituito, come ho commentato sulla sua risposta. –

16

Come altri hanno già detto, il suo scopo principale è quello di rimuovere const dagli oggetti per passare a funzioni corrette non const che sapete non modificheranno l'argomento.

C'è un trucco (di Meyers?) Per evitare la duplicazione del codice, e va così:

struct foo 
{ 
    const return_type& get(void) const 
    { 
     // fancy pants code that you definitely 
     // don't want to repeat 

     return theValue; // and got it 
    } 

    return_type& get(void) 
    { 
     // well-defined: Add const to *this, 
     // call the const version, then 
     // const-cast to remove const (because 
     // *this is non-const, this is ok) 
     return const_cast<return_type&>(static_cast<const foo&>(*this).get()); 
    } 
}; 
+7

Penso che questo trucco sia quasi sempre peggiore della duplicazione dei contenuti di 'get() const' in' get() '. Nei casi in cui questo è meglio di copia e incolla, un template helper (istanziato una volta per const e una volta per non-const) sarebbe ancora meglio, poiché permetterebbe al compilatore di verificare che il codice dei pantaloni di fantasia restituisca qualcosa di modificabile nel caso in cui 'questo' sia modificabile. Potrebbe non farlo, a volte potrebbe restituire un riferimento a una variabile globale 'const', quindi questo trucco ti obbliga a verificare manualmente la costitutività del codice dei pantaloni di fantasia. Cattivo. –

+1

@Steve: preferirei fare questo copia incolla. Nel caso speciale in cui questo trucco non funziona, non usarlo. – GManNickG

+1

Cosa succede se il codice "fancy pants" è 0 righe e "get' restituisce solo un membro dati? Vuoi evitare di copiare e incollare? La mia richiesta è che non ci siano casi validi per questo trucco.O il codice è abbastanza semplice da copiare e incollare, oppure è troppo complesso da analizzare manualmente per la cost-correttezza. Non c'è via di mezzo che sia troppo da copiare, ma abbastanza poco da non volere la cost-correttezza automatica. Nell'esempio di Meyer IIRC il codice di fantasia è un controllo dei limiti: quindi metti il ​​check in una funzione di supporto, nello stesso modo in cui normalmente condividiamo il codice ;-) –

4

legittima uso (secondo me) è con gli iteratori std::set. Sono sempre const, per evitare di cambiare la chiave utilizzata nel set. La modifica della chiave interromperebbe la struttura interna dell'insieme e causerebbe un comportamento indefinito.

Tuttavia, finché la chiave non cambia, è possibile modificare altri dati nell'oggetto.

Diciamo che avete un std::set come questo:

std::set<MyObject> some_set; 

E una classe come questa:

class MyObject { 
    public: 
     MyObject(const std::string &key) 
      : key_(key) {} 

     bool operator<(const MyObject &other) const { 
      return key_ < other.key_; 
     } 

    private: 
     // ... 
     // <some other data> 
     // ... 

     const std::string key_; 
}; 

Nell'esempio precedente, il tasto è già const, quindi, anche se modificare l'oggetto, non è possibile rompere la struttura interna del set.

Normalmente si può ottenere solo un riferimento const da un iteratore set:

const MyObject &object = *some_set_iterator; 

Ma dal momento che la chiave è const, è sicuro di const_cast l'iteratore Dereferenced:

MyObject &object = const_cast<MyObject &>(*some_set_iterator);