Const_cast è sicuro?


92

Non riesco a trovare molte informazioni su const_cast. Le uniche informazioni che sono riuscito a trovare (su Stack Overflow) sono:

La const_cast<>()è usato per aggiungere / rimuovere const (Ness) (o volatili-Ness) di una variabile.

Questo mi rende nervoso. L'utilizzo di un const_castcomportamento imprevisto potrebbe causare? E allora?

In alternativa, quando è possibile utilizzarlo const_cast?


4
La risposta principale trascura qualcosa che potrebbe essere orribilmente ovvio, ma vale la pena affermarlo: diventa pericoloso solo se si tenta di modificare un constoggetto originariamente tramite un constriferimento / puntatore annullato. Se, invece, stai semplicemente const_castcercando di aggirare un'API scarsamente (o, nel mio caso, pigramente) specificata che accetta solo un non constriferimento ma verrà utilizzata solo nei constmetodi ... nessun problema di sorta.
underscore_d

1
@underscore_d: una versione più precisa della domanda (e della risposta) che copre questa è: è consentito eliminare const su un oggetto definito da const fintanto che non è effettivamente modificato?
Peter Cordes

Risposte:


88

const_castè sicuro solo se stai eseguendo il casting di una variabile che originariamente non era const. Ad esempio, se si dispone di una funzione che accetta un parametro di a const char *e si passa a un modificabile char *, è sicuro const_castriportare quel parametro a a char *e modificarlo. Tuttavia, se la variabile originale era in effetti const, l'utilizzo const_castrisulterà in un comportamento indefinito.

void func(const char *param, size_t sz, bool modify)
{
    if(modify)
        strncpy(const_cast<char *>(param), sz, "new string");
    printf("param: %s\n", param);
}

...

char buffer[16];
const char *unmodifiable = "string constant";
func(buffer, sizeof(buffer), true);  // OK
func(unmodifiable, strlen(unmodifiable), false); // OK
func(unmodifiable, strlen(unmodifiable), true);  // UNDEFINED BEHAVIOR

9
Non è vero. Standard C ++. §7.1.​5.1/4 says Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior Qualsiasi tentativo ! Non ci sono parole sulla variabile originale.
Alexey Malistov

20
@Alexey: la variabile originale riguarda ciò a cui si fa riferimento o a cui si fa riferimento. È possibile prendere un riferimento const a un oggetto non const e, pertanto, eseguire il cast di un riferimento scrivibile è un comportamento ben definito poiché l'oggetto a cui si fa riferimento non è effettivamente const.
Cucciolo

43
@Alexey Malistov: No. Un "oggetto" si riferisce all'effettiva regione di archiviazione occupata nella memoria (§1.7). Prendere un riferimento const a un oggetto non const non rende l'oggetto const. Solo nel caso di un parametro di riferimento const ( non un parametro puntatore const) il compilatore è autorizzato a fare una copia silenziosamente (§5.2.2 / 5); questo non è il caso qui.
Adam Rosenfield,

8
"Tuttavia, se la variabile originale era in effetti const, l'utilizzo di const_cast risulterà in un comportamento indefinito" Questa affermazione è falsa.
Gare di leggerezza in orbita il

7
E ' non è UB utilizzare const_castper rimuovere constda qualcosa che è stato inizialmente dichiarato const. Ma è UB a provare effettivamente a scrivere su quell'oggetto. Finché leggi, stai bene e di const_castper sé non causa UB. È un'idea orribile, ma non è intrinsecamente UB.
Jesper Juhl

35

Posso pensare a due situazioni in cui const_cast è sicuro e utile (potrebbero esserci altri casi validi).

Uno è quando si dispone di un'istanza, di un riferimento o di un puntatore const e si desidera passare un puntatore o un riferimento a un'API che non è corretto per const, ma che si è CERTI di non modificare l'oggetto. Puoi const_cast il puntatore e passarlo all'API, confidando che non cambierà davvero nulla. Per esempio:

void log(char* text);   // Won't change text -- just const-incorrect

void my_func(const std::string& message)
{
    log(const_cast<char*>(&message.c_str()));
}

L'altro è se stai usando un vecchio compilatore che non implementa 'mutable' e vuoi creare una classe che sia logicamente const ma non bit per bit. Puoi const_cast 'this' all'interno di un metodo const e modificare i membri della tua classe.

class MyClass
{
    char cached_data[10000]; // should be mutable
    bool cache_dirty;        // should also be mutable

  public:

    char getData(int index) const
    {
        if (cache_dirty)
        {
          MyClass* thisptr = const_cast<MyClass*>(this);
          update_cache(thisptr->cached_data);
        }
        return cached_data[index];
    }
};

Questo ... non sembra rispondere a questa domanda. Ha chiesto se const_castpuò causare un comportamento indefinito, non quali utili applicazioni sono
Michael Mrozek,

13
Dalla domanda: "In alternativa, quando va bene usare const_cast?"
Fred Larson

Come in "quando non è undefined"; non sta cercando esempi di quando è utile
Michael Mrozek

Possiamo solo attenerci alle lettere della domanda. Sulla base di ciò, la presentazione di un uso illustrativo di const_castè una valida risposta. Non ci sono hedomande in quanto il soggetto è solo la domanda.
eigenfield

24

Trovo difficile credere che questa sia l' unica informazione che puoi trovare su const_cast. Citando dal secondo successo di Google :

Se si elimina la costanza di un oggetto che è stato esplicitamente dichiarato come const e si tenta di modificarlo, i risultati non sono definiti.

Tuttavia, se si elimina la costanza di un oggetto che non è stato esplicitamente dichiarato come const, è possibile modificarlo in modo sicuro.


Grrrreaat risposta, combina questo con questa risposta e ottieni il quadro completo.
bobobobo

hmm. per quanto riguarda la seconda affermazione nella tua risposta, posso chiederti come esiste una "const" per un oggetto che non è stato esplicitamente dichiarato come const in primo luogo ?.
hAcKnRoCk

Esistono molti modi per rendere const, @Iam un oggetto non const. Ad esempio, passare l'oggetto come parametro di riferimento const. Oppure assegnalo a un puntatore a const. Oppure usa const_cast. Oppure chiama un metodo const su di esso.
Rob Kennedy

12

Quello che dice Adam. Un altro esempio in cui const_cast può essere utile:

struct sample {
    T& getT() { 
        return const_cast<T&>(static_cast<const sample*>(this)->getT()); 
    }

    const T& getT() const { 
       /* possibly much code here */
       return t; 
    }

    T t;
};

Per prima cosa aggiungiamo const al tipo a cui thispunta, quindi chiamiamo la versione const di getTe quindi rimuoviamo const dal tipo restituito, che è valido poiché tdeve essere non const (altrimenti, la versione non const di getTnon potrebbe avere stato chiamato). Questo può essere molto utile se hai un corpo di funzione di grandi dimensioni e vuoi evitare il codice ridondante.


3
Preferisco usare il cast statico per l'aggiunta di constness: static_cast <const sample *> (this). Quando leggo const_cast significa che il codice sta facendo qualcosa di potenzialmente pericoloso, quindi cerco di evitarlo quando possibile.
mfazekas

1
giusto, il primo può essere static_cast, o anche implicit_cast (di boost). lo aggiusterò usando il cast statico. grazie
Johannes Schaub - litb

3
Vado avanti e indietro sul fatto che const_casto static_castè meglio. const_castpuò fare solo quello che vuoi: cambiare i qualificatori cv. static_castpuò eseguire "silenziosamente" altre operazioni che non si intende. Tuttavia, il primo cast è completamente sicuro e static_casttende ad essere più sicuro di const_cast. Penso che questa sia una situazione in cui const_castcomunica meglio il tuo intento, ma static_castcomunica meglio la sicurezza delle tue azioni.
David Stone,

10

La risposta breve è no, non è sicuro.

La risposta lunga è che se ne sai abbastanza per usarlo, allora dovrebbe essere sicuro.

Quando effettui il casting, quello che stai dicendo essenzialmente è: "So qualcosa che il compilatore non sa". Nel caso di const_cast, quello che stai dicendo è: "Anche se questo metodo accetta un riferimento o un puntatore non const, so che non cambierà il parametro, lo passo".

Quindi, se sai effettivamente cosa pretendi di sapere usando il cast, allora va bene usarlo.


5

Stai distruggendo ogni possibilità di thread-safety, se inizi a modificare cose che il compilatore pensava fossero const.


1
Che cosa? Se hai oggetti immutabili (const), puoi condividerli banalmente tra i thread. Nell'istante in cui una parte del tuo codice getta via const-ness, perdi tutta la sicurezza del tuo thread! Perché sono down-modded per questo? sigh
Matt Cruikshank

8
Const è certamente uno strumento utile per rendere il codice thread-safe, ma non fornisce alcuna garanzia (tranne nel caso delle costanti in fase di compilazione). Due esempi: un oggetto const può avere membri mutabili e avere un puntatore const a un oggetto non dice nulla sul fatto che l'oggetto stesso possa cambiare.
James Hopkin,

Penso che questa sia una buona risposta perché non ho pensato ai sentimenti di fiducia e sicurezza dell'ottimizzatore del compilatore nell'uso della parola const. constè fiducia. const_caststa infrangendo quella fiducia :(
bobobobo

1
Riguardo a mutable e thread-safety: channel9.msdn.com/posts/…
MFH

-3
#include <iostream>
using namespace std;

void f(int* p) {
  cout << *p << endl;
}

int main(void) {
  const int a = 10;
  const int* b = &a;

  // Function f() expects int*, not const int*
  //   f(b);
  int* c = const_cast<int*>(b);
  f(c);

  // Lvalue is const
  //  *b = 20;

  // Undefined behavior
  //  *c = 30;

  int a1 = 40;
  const int* b1 = &a1;
  int* c1 = const_cast<int*>(b1);

  // Integer a1, the object referred to by c1, has
  // not been declared const
  *c1 = 50;

  return 0;
}

fonte: http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fkeyword_const_cast.htm


Downvoting a causa di link spam
eigenfield
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.