C / C ++ cambiando il valore di un const

Ho avuto un articolo, ma l’ho perso. Ha mostrato e descritto un paio di trucchetti C / C ++ che le persone dovrebbero fare attenzione. Uno di loro mi ha interessato, ma ora che sto cercando di replicarlo non sono in grado di farlo compilare.

Il concetto era che è ansible cambiare per caso il valore di un const in C / C ++

Era qualcosa del genere:

 const int a = 3; // I promise I won't change a const int *ptr_to_a = &a; // I still promise I won't change a int *ptr; ptr = ptr_to_a; (*ptr) = 5; // I'm a liar; a is now 5 

Volevo mostrarlo ad un amico ma ora mi manca un passaggio. Qualcuno sa cosa manca per iniziare a compilare e lavorare?

ATM Ricevo una conversione non valida da “const int *” a “int *” ma quando ho letto l’articolo che ho provato, ha funzionato benissimo.

devi gettare via la costanza:

 linux ~ $ cat constTest.c #include  void modA( int *x ) { *x = 7; } int main( void ) { const int a = 3; // I promisse i won't change a int *ptr; ptr = (int*)( &a ); printf( "A=%d\n", a ); *ptr = 5; // I'm a liar, a is now 5 printf( "A=%d\n", a ); *((int*)(&a)) = 6; printf( "A=%d\n", a ); modA( (int*)( &a )); printf( "A=%d\n", a ); return 0; } linux ~ $ gcc constTest.c -o constTest linux ~ $ ./constTest A=3 A=5 A=6 A=7 linux ~ $ g++ constTest.c -o constTest linux ~ $ ./constTest A=3 A=3 A=3 A=3 

anche la risposta comune non funziona in g ++ 4.1.2

 linux ~ $ cat constTest2.cpp #include  using namespace std; int main( void ) { const int a = 3; // I promisse i won't change a int *ptr; ptr = const_cast( &a ); cout << "A=" << a << endl; *ptr = 5; // I'm a liar, a is now 5 cout << "A=" << a << endl; return 0; } linux ~ $ g++ constTest2.cpp -o constTest2 linux ~ $ ./constTest2 A=3 A=3 linux ~ $ 

btw .. questo non è mai raccomandato ... Ho trovato che g ++ non permette che questo accada .. quindi potrebbe essere il problema che stai vivendo.

Solo una supposizione, ma una domanda comune è perché uno non può convertire un int** in un const int** , che a prima vista sembra ragionevole (dopotutto, stai solo aggiungendo un const , che normalmente è ok) . Il motivo è che se si potesse fare questo, si potrebbe modificare accidentalmente un object const :

 const int x = 3; int *px; const int **ppx = &px; // ERROR: conversion from 'int**' to 'const int**' *ppx = &x; // ok, assigning 'const int*' to 'const int*' *px = 4; // oops, just modified a const object 

È un risultato non intuitivo, ma l’unico modo per assicurarsi che non si possa modificare un object const in questo caso (si noti come non ci siano caratteri tipografici) è di fare della linea 3 un errore.

Ti è permesso solo aggiungere const senza un cast al PRIMO livello di indirezione:

 int * const *ppx = &px; // this is ok *ppx = &x; // but now this is an error because *ppx is 'const' 

In C ++, è imansible modificare un object const senza usare un typecast di qualche tipo. Dovrai usare un cast di tipo C o uno stile C ++ per rimuovere la costanza. Qualsiasi altro tentativo di farlo risulterà in un errore del compilatore da qualche parte.

Nota che qualsiasi tentativo di eliminare la costanza non è definito dallo standard. Dal 7.1.5.1 dello standard:

Tranne che qualsiasi membro della class dichiarato mutabile può essere modificato, qualsiasi tentativo di modificare un object const durante la sua vita determina un comportamento indefinito.

E subito dopo questo esempio è usato:

 const int* ciq = new const int (3); // initialized as required int* iq = const_cast(ciq); // cast required *iq = 4; // undefined: modifies a const object 

Quindi, in breve, quello che vuoi fare non è ansible usando il C ++ standard.

Inoltre, quando il compilatore incontra una dichiarazione come

 const int a = 3; // I promisse i won't change a 

è libero di sostituire qualsiasi occorrenza di ‘a’ con 3 (facendo effettivamente la stessa cosa di #define a 3 )

Tornando nella notte dei tempi, i paleo-programmatori usavano FORTRAN. FORTRAN ha passato tutti i suoi parametri per riferimento e non ha eseguito alcun controllo ortografico. Ciò significava che era abbastanza facile cambiare accidentalmente il valore di anche una costante letterale. Potresti passare “3” a un SUBROUTINE, e sarebbe tornato cambiato, e così ogni volta da quel momento in cui il tuo codice aveva un “3”, in realtà si comporterebbe come un valore diverso. Lascia che te lo dica, quelli erano insetti difficili da trovare e risolvere.

Hai provato questo?

 ptr = const_cast(ptr_to_a); 

Questo dovrebbe aiutarlo a compilare, ma non è davvero un caso a causa del cast.

In C ++, utilizzando Microsoft Visual Studio-2008

 const int a = 3; /* I promisse i won't change a */ int * ptr1 = const_cast (&a); *ptr1 = 5; /* I'm a liar, a is now 5 . It's not okay. */ cout << "a = " << a << "\n"; /* prints 3 */ int arr1[a]; /* arr1 is an array of 3 ints */ int temp = 2; /* or, const volatile int temp = 2; */ const int b = temp + 1; /* I promisse i won't change b */ int * ptr2 = const_cast (&b); *ptr2 = 5; /* I'm a liar, b is now 5 . It's okay. */ cout << "b = " << b << "\n"; /* prints 5 */ //int arr2[b]; /* Compilation error */ 

In C, una variabile const può essere modificata attraverso il suo puntatore; tuttavia è un comportamento indefinito. Una variabile const non può mai essere utilizzata come lunghezza in una dichiarazione di array.

In C ++, se una variabile const viene inizializzata con un'espressione costante pura, il suo valore non può essere modificato tramite il puntatore nemmeno dopo aver tentato di modificarlo, altrimenti una variabile const può essere modificata tramite il puntatore.

Una variabile const integrale pura può essere usata come lunghezza in una dichiarazione di matrice, se il suo valore è maggiore di 0.

Un'espressione costante pura è costituita dai seguenti operandi.

  1. Un valore letterale numerico (costante) ad es. 2, 10.53

  2. Una costante simbolica definita dalla direttiva #define

  3. Una costante di enumerazione

  4. Una variabile const pura cioè una variabile const che è a sua volta inizializzata con una pura espressione costante.

  5. Non sono consentite variabili non const o variabili volatili.

Probabilmente vuoi usare const_cast:

 int *ptr = const_cast(ptr_to_a); 

Non sono sicuro al 100% che funzioni, però sono un po ‘arrugginito in C / C ++ 🙂

Alcuni readup per const_cast: http://msdn.microsoft.com/en-us/library/bz6at95h(VS.80).aspx

 const int foo = 42; const int *pfoo = &foo; const void *t = pfoo; void *s = &t; // pointer to pointer to int int **z = (int **)s; // pointer to int **z = 0; 

L’articolo che stavi guardando potrebbe aver parlato della differenza tra

 const int *pciCantChangeTarget; const int ci = 37; pciCantChangeTarget = &ci; // works fine *pciCantChangeTarget = 3; // compile error 

e

 int nFirst = 1; int const *cpiCantChangePointerValue = &nFirst; int nSecond = 968; *pciCantChangePointerValue = 402; // works cpiCantChangePointerValue = &ci; // compile error 

O così ricordo – non ho nulla ma gli strumenti Java qui, quindi non posso testare 🙂

 #include int main( void ) { int i = 3; const int *pi = &i; int *pj = (int*)&i; *pj = 4; getchar(); return 0; } 

possiamo cambiare il valore della variabile const con il seguente codice:

 const int x=5; printf("\nValue of x=%d",x); *(int *)&x=7; printf("\nNew value of x=%d",x); 

Stavo cercando su come convertire tra i conts e ho trovato questo http://www.possibility.com/Cpp/const.html forse può essere utile a qualcuno. 🙂

Ho testato il codice qui sotto e cambia con successo le variabili membro costante.

 #include  class A { private: int * pc1; // These must stay on the top of the constant member variables. int * pc2; // Because, they must be initialized first int * pc3; // in the constructor initialization list. public: A() : c1(0), c2(0), c3(0), v1(0), v2(0), v3(0) {} A(const A & other) : pc1 (const_cast(&other.c1)), pc2 (const_cast(&other.c2)), pc3 (const_cast(&other.c3)), c1 (*pc1), c2 (*pc2), c3 (*pc3), v1 (other.v1), v2 (other.v2), v3 (other.v3) { } A(int c11, int c22, int c33, int v11, int v22, int v33) : c1(c11), c2(c22), c3(c33), v1(v11), v2(v22), v3(v33) { } const A & operator=(const A & Rhs) { pc1 = const_cast(&c1); pc2 = const_cast(&c2), pc3 = const_cast(&c3), *pc1 = *const_cast(&Rhs.c1); *pc2 = *const_cast(&Rhs.c2); *pc3 = *const_cast(&Rhs.c3); v1 = Rhs.v1; v2 = Rhs.v2; v3 = Rhs.v3; return *this; } const int c1; const int c2; const int c3; int v1; int v2; int v3; }; std::wostream & operator<<(std::wostream & os, const A & a) { os << a.c1 << '\t' << a.c2 << '\t' << a.c3 << '\t' << a.v1 << '\t' << a.v2 << '\t' << a.v3 << std::endl; return os; } int wmain(int argc, wchar_t *argv[], wchar_t *envp[]) { A ObjA(10, 20, 30, 11, 22, 33); A ObjB(40, 50, 60, 44, 55, 66); A ObjC(70, 80, 90, 77, 88, 99); A ObjD(ObjA); ObjB = ObjC; std::wcout << ObjA << ObjB << ObjC << ObjD; system("pause"); return 0; } 

L'output della console è:

 10 20 30 11 22 33 70 80 90 77 88 99 70 80 90 77 88 99 10 20 30 11 22 33 Press any key to continue . . . 

Qui, l'handicap è, devi definire tanti puntatori quante sono le variabili membro costante che hai.

questo creerà un errore di runtime. Perché l’ int è statico . Eccezione non gestita. Posizione di scrittura della violazione di accesso 0x00035834.

 void main(void) { static const int x = 5; int *p = (int *)x; *p = 99; //here it will trigger the fault at run time } 

Alcune di queste risposte indicano che il compilatore può ottimizzare la variabile ‘a’ poiché è dichiarata const . Se vuoi davvero essere in grado di cambiare il valore di a devi contrassegnarlo come volatile

  const volatile int a = 3; // I promise i won't change a int *ptr = (int *)&a; (*ptr) = 5; // I'm a liar, a is now 5 

Ovviamente, dichiarare qualcosa come const volatile dovrebbe davvero illustrare quanto sia sciocco questo.

Il passo che ti manca è che non hai bisogno del puntatore int *. La linea:

 const int *ptr_to_a = &a; // I still promiss i won't change a; 

in realtà dice che non cambierai ptr_to_a, non a. Quindi se hai cambiato il tuo codice per leggere in questo modo:

 const int a = 3; // I promise I won't change a const int *ptr_to_a = &a; // I promise I won't change ptr_to_a, not a. (*ptr_to_a) = 5; // a is now 5 

a è ora 5. Puoi cambiare a attraverso ptr_to_a senza alcun avviso.

MODIFICARE:

Quanto sopra non è corretto. Risulta che stavo confondendo un trucco simile con un shared_ptr, in cui è ansible ottenere l’accesso al puntatore raw e modificare il valore dei dati interni senza distriggersre alcun avviso. Questo è:

 #include  #include  int main() { const boost::shared_ptr* a = new boost::shared_ptr(new int(3)); *(a->get()) = 5; std::cout << "A is: " << *(a->get()) << std::endl; return 0; } 

Produrrà 5.