 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
marbac Guest
|
Posted: Mon Apr 19, 2004 2:12 pm Post subject: const_cast problem |
|
|
Hallo,
arbeite mich gerade durch die 4 casting-Typen durch und bin bei
const_cast auf folgendes Problem getroffen, welches mir ein wenig
Kopfzerbrechen bereitet ... siehe Kommentare:
Kompiler:
g++ (GCC) 3.3.1
Code:
#include <iostream>
using namespace std;
int main ()
{
const int k=666;
int *u=const_cast<int*>(&k);
*u=777;
// sollte hier k nicht 777 zugewiesen werden?
cout <<"k="<< k << " ; *u=" << *u << endl;
// Unterschiedliche Werte! Ich teste mal die Adressen:
if (&k==u) cout << "Adressen sind gleich!!!" << endl;
else cout << "Adressen sind ungleich" << endl;
// Gleiche Adressen! Unterschiedliche Werte???
// Kann ich für diesen Fall keinen const_cast verwenden?
}
Ausgabe:
k=666 ; *u=777
Adressen sind gleich!!!
Grüße marbac
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Heinz Ozwirk Guest
|
Posted: Tue Apr 20, 2004 6:45 am Post subject: Re: const_cast problem |
|
|
"marbac" <marbac (AT) chello (DOT) at> schrieb im Newsbeitrag news:h7Rgc.495607$Or1.253696 (AT) news (DOT) chello.at...
| Quote: | const int k=666;
int *u=const_cast<int*>(&k);
*u=777;
// sollte hier k nicht 777 zugewiesen werden?
|
Du begiebst dich in die dunklen Ecken des undefinierten (oder nicht spezifizierten) Verhaltens. Das Verhalten von const_cast ist nur definiert, wenn das Objekt, von dem du const entfernen willst, tief in seinem Inneren auch nicht const ist. Wenn auf ein an sich veränderliches Objekt ein const-Pointer erzeugt wurde, kann man dieses const mit const_cast wieder loswerden. Aber in deinem Fall ist k const und darauf verlässt der Compiler sich.
| Quote: | cout <<"k="<< k << " ; *u=" << *u << endl;
|
Hier geht der Compiler davon aus, dass k const ist und daher seit der Initialisierung nicht verändert wurde. Also kann er hier einfacheren Code erzeugen, nämlich
cout << "k=" << 666 << ...
| Quote: | // Kann ich für diesen Fall keinen const_cast verwenden?
|
Ganz offensichtlich nicht... und außerdem soll man den Compiler nie anlügen.
Heinz
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Martin Gieseking Guest
|
Posted: Tue Apr 20, 2004 7:28 am Post subject: Re: const_cast problem |
|
|
marbac <marbac (AT) chello (DOT) at> wrote:
| Quote: | #include <iostream
using namespace std;
int main ()
{
const int k=666;
int *u=const_cast
*u=777;
// sollte hier k nicht 777 zugewiesen werden?
cout <<"k="<< k << " ; *u=" << *u << endl;
// Unterschiedliche Werte! Ich teste mal die Adressen:
if (&k==u) cout << "Adressen sind gleich!!!" << endl;
else cout << "Adressen sind ungleich" << endl;
// Gleiche Adressen! Unterschiedliche Werte???
// Kann ich für diesen Fall keinen const_cast verwenden?
}
|
Das Verhalten des Compilers ist schon richtig. const_cast bewirkt ja nicht
die Beseitigung der Konstantheit vom Ursprungsobjekt, sondern liefert in
deinem Fall lediglich einen Zeiger auf ein Objekt, das vom Compiler bei
allen weiteren Typprüfungen als nicht konstant betrachtet wird. Das Objekt
selbst kann dabei in einem Nur-Lese-Bereich des Speichers liegen. Eine
Änderung des Ursprungsobjekts ist nach einem const_cast nur möglich, wenn
es bei seiner Definition nicht const ist.
Martin
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Werner Salomon Guest
|
Posted: Tue Apr 20, 2004 7:46 am Post subject: Re: const_cast problem |
|
|
marbac <marbac (AT) chello (DOT) at> wrote
| Quote: | Kompiler:
g++ (GCC) 3.3.1
Code:
#include <iostream
using namespace std;
int main () {
const int k=666;
int *u=const_cast
*u=777;
// sollte hier k nicht 777 zugewiesen werden?
cout <<"k="<< k << " ; *u=" << *u << endl;
// Unterschiedliche Werte! Ich teste mal die Adressen:
if (&k==u) cout << "Adressen sind gleich!!!" << endl;
else cout << "Adressen sind ungleich" << endl;
}
Ausgabe:
k=666 ; *u=777
Adressen sind gleich!!!
|
Hallo Marbac,
ich habe das ganze mal auf MS VC++ 6 ausprobiert. Der Effekt ist der
gleiche. Der Geck ist, dass mit
*u = 777;
der Variablen (!) 'k' tatsächlich der Wert 777 zugewiesen wird. Nur
bei
cout << "k=" << k ..
wird nicht die Variable 'k' sondern die Konstante 666 ausgegeben.
Der const_cast funktioniert also einwandfrei!
Versuch mal:
#include
using namespace std;
int main () {
const int k=666;
int *u=const_cast<int*>(&k);
const int* u2 = &k; // zeigt auf die Variable hinter 'k'
*u=777; // Die Variable hinter 'k' wird zu 777
cout <<"k="<< k << " ; *u=" << *u << endl;
cout << "*u2=" << *u2 << endl;
return 0;
}
Ich vermute es ist kein Bug sondern ein Feature und hängt damit
zusammen, wir 'constant expressions' in C++ behandelt werden.
Gruß
Werner
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Martin Kaul Guest
|
Posted: Tue Apr 20, 2004 8:38 am Post subject: Re: const_cast problem |
|
|
Hi
marbac wrote:
| Quote: | #include <iostream
using namespace std;
int main ()
{
const int k=666;
int *u=const_cast
*u=777;
// sollte hier k nicht 777 zugewiesen werden?
cout <<"k="<< k << " ; *u=" << *u << endl;
// Unterschiedliche Werte! Ich teste mal die Adressen:
if (&k==u) cout << "Adressen sind gleich!!!" << endl;
else cout << "Adressen sind ungleich" << endl;
// Gleiche Adressen! Unterschiedliche Werte???
// Kann ich für diesen Fall keinen const_cast verwenden?
}
Ausgabe:
k=666 ; *u=777
Adressen sind gleich!!!
Der Compiler optimiert den Aufruf von "cout <<"k="<< k", da |
er durch "const int k=666" ja weiss, dass k immer 666 ist,
d.h. beim cout Aufruf verwendet er nicht den Inhalt von k
sondern schreibt in den Assemblercode gleich die Zahl 666 rein.
Wenn ich nach der Zeile "*u=777;" noch ein "int x=k" einfuege,
dann steht bei mir im BCB6 CPU Fenster folgendes:
Unit1.cpp.11: int x = k;
004012B0 C745F49A020000 mov [ebp-0x0C], 0x0000029a
d.h. die Variable x wird intern durch "[ebp-0x0C]" representiert
und dort die Konstante 0x0000029a(hex) (=666 dez) reingeschrieben.
Find ich vom Compiler korrekt...
tschaule
Martin
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Olaf Krzikalla Guest
|
Posted: Tue Apr 20, 2004 10:05 am Post subject: Re: const_cast problem |
|
|
Hi,
Werner Salomon wrote:
| Quote: | Ich vermute es ist kein Bug sondern ein Feature und hängt damit
zusammen, wir 'constant expressions' in C++ behandelt werden.
Es ist ein Bug, allerdings nicht im Compiler, sondern im Programm. Die |
Zeilen
| Quote: | const int k=666;
int *u=const_cast<int*>(&k);
|
ergeben zur Laufzeit zusammen undefiniertes Verhalten, da das const von
einem ursprünglich konstanten Objekt weggecastet wird. Insofern ist es
auch falsch, an dieser Stelle in irgendeiner Weise von einem korrekten
(oder weniger korrekten) Compilerverhalten zu sprechen.
MfG
Olaf Krzikalla
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Friedhelm Hoerner Guest
|
Posted: Tue Apr 20, 2004 1:05 pm Post subject: Re: const_cast problem |
|
|
marbac <marbac (AT) chello (DOT) at> wrote
| Quote: | Hallo,
arbeite mich gerade durch die 4 casting-Typen durch und bin bei
const_cast auf folgendes Problem getroffen, welches mir ein wenig
Kopfzerbrechen bereitet ... siehe Kommentare:
Kompiler:
g++ (GCC) 3.3.1
Code:
#include <iostream
using namespace std;
int main ()
{
const int k=666;
int *u=const_cast
*u=777;
// sollte hier k nicht 777 zugewiesen werden?
cout <<"k="<< k << " ; *u=" << *u << endl;
// Unterschiedliche Werte! Ich teste mal die Adressen:
if (&k==u) cout << "Adressen sind gleich!!!" << endl;
else cout << "Adressen sind ungleich" << endl;
// Gleiche Adressen! Unterschiedliche Werte???
// Kann ich für diesen Fall keinen const_cast verwenden?
}
Ausgabe:
k=666 ; *u=777
Adressen sind gleich!!!
Grüße marbac
|
Wie man ggf. im C++-Standard nachlesen kann, führt ein const_cast bei
"echt konstanten" Variablen zu undefiniertem Verhalten. Daher kann der
Compiler damit machen was er will (Angeblich inclusive Code erzeugen,
der die Festplattte formatiert = )...
Da der Compiler aber doch auch logisch programmiert ist, ist das
Verhalten schon nachvollziehbar und das compilierte Programm wird die
Platte wohl nicht formatieren;-).
Als (vermutete) Erklärung folgendes:
Zuerst hast Du dem Compiler gesagt, daß k konstant ist und den Wert
666 enthält.
Daher wird der Compiler in allen Fällen wo der Wert von k gefragt ist
666 einsetzen, denn das spart Platz und Laufzeit. Das erklärt den
ersten Teil (k=666) bei cout.
Mit der Definition von int* u braucht der Compiler eine Adresse für k
- also packt er k in den Speicher (initialisiert mit 666) und gibt die
Adresse an u weiter.
Der const_cast ist eine Lüge, aber der Compiler geht davon aus, daß
der Programmierer weiß was er tut, wenn er castet (stimmt das
wirklich?) und gibt keine Meldung aus.
Wenn der Compiler k in Schreibgeschützten Speicher legt, dann erzeugt
der Schreibzugriff eine Laufzeit-exception.
Die Zuweisung von 777 erzeugt keine Exception (schgreibgeschützter
Speicher ist selten verwendet - oder unterstützt) und das Programm
läuft weiter. Jetzt steht 777 an besagter Stelle im Speicher. Das
erklärt den zweiten Teil (u=777) bei cout.
Die Adresse in u und die Adresse von k (sie ist ja für Adresszugriffe
erzeugt worden) stimmen natürlich weiterhin überein, aber wo der
Compiler k sieht ersetzt er dies weiter mit 666.
Das ist nur meine Interpretation dises Vorgangs und ändert nichts an
der Grundsätzlichen Aussage: "Das ist undefiniertes verhalten".
Manchmal ist es vielleicht wirklich nötig const "wegzucasten", aber
das funktioniert nur dann korrrekt und definiert, wenn die Variable
nicht wirklich const angelegt wurde.
Also beispielsweise bei const-Parametern einer Funktion, der man
temporäre Objekte mitgeben will und wo bekannt ist, daß sie nie mit
"echt konstanten" Daten aufgerufen wird.
Es grenzt - je nach Standpunkt - an schlechten Stil.
Gruss Friedhelm
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Markus Breuer Guest
|
Posted: Tue Apr 20, 2004 1:09 pm Post subject: Re: const_cast problem |
|
|
| Quote: | const int k=666;
int *u=const_cast<int*>(&k);
*u=777;
// sollte hier k nicht 777 zugewiesen werden?
|
Hallo marbac,
das ist ein Fehler in deinem Programm. Mit dem const_cast sagst du dem
Compiler, er soll das const ignorieren, weil du nun darauf acht geben
willst. Allerdings ignorierst du es und überschreibst verbotenerweise
die const-variable. Eine const-variable darf in keinem Fall zur Laufzeit
modifiziert werden, auch nicht nach einem const_cast!
Der const_cast dient ausschließlich der Rückwärtskompatibilität zu alten
C-Bibliotheken, die das Schlüsselwort const nicht kennen. Beispielweise
in alten Versionen von strcmp(char*,char*). Hier weisst du, dass die
Argumente nur gelesen werden und entfernst das const von deiner
Variablen. Andernfalls könntest du den Code gar nicht kompilieren.
Gruß Markus
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Falk Tannhäuser Guest
|
Posted: Tue Apr 20, 2004 2:06 pm Post subject: Re: const_cast problem |
|
|
Friedhelm Hoerner wrote:
| Quote: | Wenn der Compiler k in Schreibgeschützten Speicher legt, dann erzeugt
der Schreibzugriff eine Laufzeit-exception.
Die Zuweisung von 777 erzeugt keine Exception (schgreibgeschützter
Speicher ist selten verwendet - oder unterstützt) und das Programm
läuft weiter. Jetzt steht 777 an besagter Stelle im Speicher. Das
erklärt den zweiten Teil (u=777) bei cout.
|
Wenn die Variable k global (also außerhalb von main) definiert ist,
macht's bei mir mit gcc 3.3.1 (cygwin) tatsächlich "Bums" (Signal 11),
da k in einem Nur-Lese-Segment abgelegt wird. (Wenn der Prozessor / das
OS keine solchen Schutzmechanismen unterstützt, kann das natürlich ganz
anders aussehen - siehe z.B. das gute alte MS-DOS vor 15 Jahren).
Ist k lokal und gcc 3.3.1 erkennt, dass deren Adresse genommen wird,
wird dagegen Speicher auf dem Stack reserviert, welcher natürlich
nicht schreibgeschützt ist.
All das sind mögliche / erlaubte Manifestationen von laut Standard "nicht
definiertem Verhalten". Unter MS-DOS wäre es tatsächlich denkbar (wenn
auch nicht wahrscheinlich), dass ein solches Programm dummerweise nach
Speicherkorruption die BIOS-Routine zum Festplattenformatieren aufruft...
MfG
Falk
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Falk Tannhäuser Guest
|
Posted: Tue Apr 20, 2004 2:42 pm Post subject: Re: const_cast problem |
|
|
Markus Breuer wrote:
| Quote: | Der const_cast dient ausschließlich der Rückwärtskompatibilität zu alten
C-Bibliotheken, die das Schlüsselwort const nicht kennen. Beispielweise
in alten Versionen von strcmp(char*,char*). Hier weisst du, dass die
Argumente nur gelesen werden und entfernst das const von deiner
Variablen. Andernfalls könntest du den Code gar nicht kompilieren.
|
'const_cast' kann auch nützlich sein, wenn man eine (Member- oder freie)
Funktion sowohl mit mit als auch ohne 'const'-Interface überladen braucht
und eine der beiden Versionen zwecks Vermeidung von Kode-Duplizierung
(welche stets Pöse(tm) ist) mit Hilfe der anderen implementiert werden soll.
Also z.B.
_____________________________________________________________________
class MeineMatrix
{
double daten[GANZ_VIEL];
// ...
public:
// ...
double const& operator()(unsigned i, unsigned j) const;
double& operator()(unsigned i, unsigned j)
{
MeineMatrix const& const_icke = *this;
return const_cast<double&>( const_icke(i, j) ); // !!!
// Könnte man auch in einer Zeile schreiben:
// return const_cast<double&>( const_cast<MeineMatrix const*>(this)->operator()(i, j) );
}
};
double const& MeineMatrix::operator()(unsigned i, unsigned j) const
{
if(i >= WAT || j >= NOCHWAT )
throw ...;
// Waaahnsinnig komplizierte Indexberechnungen in 250 Programmzeilen,
// die aber *this nicht modifizieren
return daten[ (BLUPP * i + BLAH * j) % GANZ_VIEL ];
}
_____________________________________________________________________
Hier ist der 'const_cast' in der Zeile '// !!!' sicher, solange die
'const'-Version des Operators stets eine Referenz auf ein (nicht-konstantes)
Daten-Member von '*this' zurückgibt, da man ja weiß, dass '*this' an
dieser Stelle nicht konstant ist.
Natürlich hätte man auch den gleichen Kode in beide Implementierungen
reinkopieren können - ist aber Pöse(tm)...
MfG
Falk
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Tue Apr 20, 2004 5:17 pm Post subject: Re: const_cast problem |
|
|
Friedhelm Hoerner wrote:
| Quote: | Wie man ggf. im C++-Standard nachlesen kann, führt ein const_cast bei
"echt konstanten" Variablen zu undefiniertem Verhalten. Daher kann der
Compiler damit machen was er will (Angeblich inclusive Code erzeugen,
der die Festplattte formatiert = )...
|
In C-Newsgroups wird auch gerne davon gesprochen, daß dir Code mit
undefiniertem Verhalten sogar Dämonen aus der Nase fliegen lassen,
deinem Boss eine böse Email schicken oder einen thermonuklearen
Weltkrieg auslösen könnte. Das ist zwar auch alles eher
unwahrscheinlich, aber auch diese Reaktionen wären durchaus von der
C++-Norm erlaubt. Natürlich kann das Ergebnis noch von beliebigen
Faktoren abhängen, z.B. ob die Pins der CPU nach Süden ausgerichtet
sind oder ob man vorher eine Ziege über dem SCSI-Bus geopfert hat.
| Quote: | Da der Compiler aber doch auch logisch programmiert ist, ist das
Verhalten schon nachvollziehbar und das compilierte Programm wird die
Platte wohl nicht formatieren;-).
|
Naja, die Idee dieser eher krassen Szenarienbeschreibungen ist auch
eher, dem Leser beizubringen, daß er _NIEMALS_ wissentlich
undefiniertes Verhalten hervorrufen sollte und auch am besten nicht
versuchen sollte, zu ergründen, was genau passiert und warum es das
tut. Das ist auch eher unwichtig. Wichtig ist nur, daß man es nicht tun
sollte.
| Quote: | Als (vermutete) Erklärung folgendes:
Zuerst hast Du dem Compiler gesagt, daß k konstant ist und den Wert
666 enthält.
Daher wird der Compiler in allen Fällen wo der Wert von k gefragt ist
666 einsetzen, denn das spart Platz und Laufzeit. Das erklärt den
ersten Teil (k=666) bei cout.
|
Naja, bei 666 kann das Ergebnis ja nur böse sein :-)
| Quote: | Mit der Definition von int* u braucht der Compiler eine Adresse für k
- also packt er k in den Speicher (initialisiert mit 666) und gibt die
Adresse an u weiter.
Der const_cast ist eine Lüge, aber der Compiler geht davon aus, daß
der Programmierer weiß was er tut, wenn er castet (stimmt das
wirklich?) und gibt keine Meldung aus.
|
So ist es. Ein cast ist immer eine Anweisung der Art "halt die Klappe,
ich weiß, was ich tue". Umso wichtiger ist es natürlich, einen Cast nur
dann einzusetzen, wenn man dann auch wirklich weiß, was man tut.
| Quote: | Das ist nur meine Interpretation dises Vorgangs und ändert nichts an
der Grundsätzlichen Aussage: "Das ist undefiniertes verhalten".
Manchmal ist es vielleicht wirklich nötig const "wegzucasten", aber
das funktioniert nur dann korrrekt und definiert, wenn die Variable
nicht wirklich const angelegt wurde.
|
Oder man das Resultat des const_cast nicht zum Schreiben benutzt. Wenn
man Code benutzt, der nicht const-korrekt programmiert wurde und den
man nicht ändern kann (z.B. eine Biblitohek), muß man manchmal
const_cast einsetzen, um die const-Fehler nicht durchs ganze Programm
zu verschleppen.
| Quote: | Also beispielsweise bei const-Parametern einer Funktion, der man
temporäre Objekte mitgeben will und wo bekannt ist, daß sie nie mit
"echt konstanten" Daten aufgerufen wird.
Es grenzt - je nach Standpunkt - an schlechten Stil.
|
const_cast ist für mich bis auf eine Ausnahme immer ein Zeichen für
einen Design- oder Implemenationsfehler. Entweder ist der Einsatz des
const_cast selbst der Fehler (wie im hier besprochenen Beispiel) oder
wird verwendet als Workaround für einen Fehler (siehe oben - Stichwort
const-korrekt).
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Markus Breuer Guest
|
Posted: Wed Apr 21, 2004 9:37 am Post subject: Re: const_cast problem |
|
|
Falk Tannhäuser schrieb:
| Quote: | Markus Breuer wrote:
Der const_cast dient ausschließlich der Rückwärtskompatibilität zu alten
C-Bibliotheken, die das Schlüsselwort const nicht kennen. Beispielweise
in alten Versionen von strcmp(char*,char*). Hier weisst du, dass die
Argumente nur gelesen werden und entfernst das const von deiner
Variablen. Andernfalls könntest du den Code gar nicht kompilieren.
'const_cast' kann auch nützlich sein, wenn man eine (Member- oder freie)
Funktion sowohl mit mit als auch ohne 'const'-Interface überladen braucht
und eine der beiden Versionen zwecks Vermeidung von Kode-Duplizierung
(welche stets Pöse(tm) ist) mit Hilfe der anderen implementiert werden soll.
Also z.B.
_____________________________________________________________________
class MeineMatrix
{
double daten[GANZ_VIEL];
// ...
public:
// ...
double const& operator()(unsigned i, unsigned j) const;
double& operator()(unsigned i, unsigned j)
{
MeineMatrix const& const_icke = *this;
return const_cast<double&>( const_icke(i, j) ); // !!!
// Könnte man auch in einer Zeile schreiben:
// return const_cast<double&>( const_cast<MeineMatrix const*>(this)->operator()(i, j) );
}
};
|
Das ist falsch! Mit dem wegcasten von const übernimmst du die
Verantwortung für die Referenz, d.h. du als Programmierer bist weiterhin
verantwortlich. Demnach gehst du in deinem Beispiel davon aus, dass das
Ergebnis beider Operatoren niemals modifiziert wird. Diesen Zweck
erfüllt schon allein der const-Operator (s.o.).
Auch wenn dein Compiler (scheinbar) funktionalen Code generiert, bleibt
das falsch. Der Hinweis const kann vom Compiler zum Zweck der
Optimierung verwendet werden, und dann kann die Variable möglicherweise
gar nicht beschrieben werden, weil sie im Falle const nur aus dem
Register statt aus dem Speicher gelesen wird. Spätestens mit inline-Code
kann der Compiler derartige Optimierungen durchführen.
Merke: const verbietet schreibenden Zugriff, das gilt auch nach einem
const_cast<>.
Gruß Markus
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Falk Tannhäuser Guest
|
Posted: Wed Apr 21, 2004 12:23 pm Post subject: Re: const_cast problem |
|
|
Markus Breuer wrote:
| Quote: |
Falk Tannhäuser schrieb:
class MeineMatrix
{
double daten[GANZ_VIEL];
// ...
public:
// ...
double const& operator()(unsigned i, unsigned j) const;
double& operator()(unsigned i, unsigned j)
{
MeineMatrix const& const_icke = *this;
return const_cast<double&>( const_icke(i, j) ); // !!!
[...]
}
};
Das ist falsch! Mit dem wegcasten von const übernimmst du die
Verantwortung für die Referenz, d.h. du als Programmierer bist weiterhin
verantwortlich. Demnach gehst du in deinem Beispiel davon aus, dass das
Ergebnis beider Operatoren niemals modifiziert wird. Diesen Zweck
erfüllt schon allein der const-Operator (s.o.).
Die Implementierung von 'double const& operator()(unsigned i, unsigned j) const' |
sei const-korrekt.
'double& operator()(unsigned i, unsigned j)' wird nur für ein MeineMatrix-Objekt
aufgerufen, dessen Zugriffspfad nicht const-qualifiziert war. (War das Objekt
selbst 'const', hat der Benutzer der Klasse rumgecasted und kriegt, was er
verdient).
In der Implementierung von 'double& operator()(unsigned i, unsigned j)'
schaffe ich einen const-qualifizierten Zugriffspfad auf dieses Objekt,
um die konstante Operator-Version aufzurufen. Ich erhalte einen const-
qualifizierten Zugriffspfad auf einen Datenmember meines Objekts.
Diesen wandle ich per const_cast in einen nicht qualifizierten um.
Er kann verwendet werden, um das Objekt zu modifizieren, was erlaubt
ist, solange dieses nicht 'const' ist (und nur dies durch Schuld des
Klassenbenutzers sein könnte).
| Quote: |
Auch wenn dein Compiler (scheinbar) funktionalen Code generiert, bleibt
das falsch. Der Hinweis const kann vom Compiler zum Zweck der
Optimierung verwendet werden, und dann kann die Variable möglicherweise
gar nicht beschrieben werden, weil sie im Falle const nur aus dem
Register statt aus dem Speicher gelesen wird. Spätestens mit inline-Code
kann der Compiler derartige Optimierungen durchführen.
So wie ich die Heilige Schrift (7.1.5.1/3) verstehe |
" A pointer or reference to a cv-qualified type need not actually point
or refer to a cv-qualified object, but it is treated as if it does;
a const-qualified access path cannot be used to modify an object <<
if the object referenced is a non-const object and can be modified
through some other access path.>>> [Note: cv-qualifiers are supported by
the type system so that they cannot be subverted without casting (5.2.11). ]
"
darf der Compiler eine solche Optimierung wegen der von mir mit <<< >>>
gekennzeichneten Passage nicht durchführen. Beispielsweise *muss* folgendes
Progrämmchen "0 1" ausgeben:
#include <iostream>
#include <ostream>
void foo(int& i, int const& ci)
{
std::cout << ci << ' ';
++i;
std::cout << ci << 'n';
}
int main()
{
int n = 0;
foo(n, n);
return 0;
}
Dies scheint mir auch durch das Heilige Beispiel aus 7.1.5.1/5 bestätigt:
" const int ci = 3; // cv-qualified (initialized as required)
ci = 4; // ill-formed: attempt to modify const
int i = 2; // not cv-qualified
const int* cip; // pointer to const int
cip = &i; // OK: cv-qualified access path to unqualified
*cip = 4; // ill-formed: attempt to modify through ptr to const
int* ip;
ip = const_cast
*ip = 4; // defined: *ip points to i, a non-const object
"
Mit meinem obigen Codebeispiel (const_cast<double&>...) befinde ich mich
in der gleichen Situation wie in diesen letzten beiden Zeilen.
Lange Rede, kurzer Sinn:
- Objekte können 'const' sein oder nicht.
- Zugriffspfade auf Objekte können 'const'-qualifiziert sein oder nicht.
- Auf ein nicht konstantes Objekt kann man sowohl nicht 'const'-qualifizierte
als auch (per i.d.R. implizitem Cast) 'const'-qualifizierte Zugriffspfade
schaffen.
- Auf ein konstantes Objekt kann man 'const'-qualifizierte Zugriffspfade
schaffen; dagegen benötigt man einen const_cast, um nicht 'const'-qualifizierte
Zugriffspfade zu schaffen.
- Der Versuch, ein beliebiges Objekt über einen 'const'-qualifizierten Zugriffspfad
zu modifizieren, wird vom Compiler abgeblockt (ill-formed program =>
Diagnosepflicht)
- Der Versuch, ein konstantes Objekt über einen nicht 'const'-qualifizierten
Zugriffspfad zu modifizieren resultiert in Nicht Definiertem Verhalten.
- Ein nicht konstantes Objekt darf modifiziert werden, selbst über einen
nicht 'const'-qualifizierten Zugriffspfad, welcher per const_cast aus
einem 'const'-qualifizierten Zugriffspfad erhalten wurde.
Alle Klarheiten beseitigt? Oder habe ich die heilige Schrift flacsh verstanden?
MfG
Falk "der findet, dass 'const' eigentlich eher 'read_only' heissen sollte" Tannhäuser
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Daniel Schüle Guest
|
Posted: Wed Apr 21, 2004 3:25 pm Post subject: Re: const_cast problem |
|
|
Hi
folgender Code konnte interessant fur dich sein
#include <iostream>
#include <cstdlib>
void const_cast_test()
{
const int a = 10;
volatile const int b = 100;
cout << a << endl;
cout << b << endl;
int * pi = const_cast
*pi = 20;
pi = const_cast<int *>(&b);
*pi = 200;
cout << a << endl;
cout << b << endl;
}
int main()
{
const_cast_test();
return EXIT_SUCCESS;
}
g++ und icc liefern die gleiche Ausgabe
10
100
10
200
allerings ist diese nicht definiert durch den Standard
(meineswissens)
was spucken die anderen Compiler weiss ich nciht
vielleicht sagt das jemand, wäre interessant
wie schon andere gesagt haben, geht der Compiler davon aus
dass der const-wert sich nicht andert und liest die Variable nicht
immer aus (was mit volatile erzwungen wird)
ciao, Daniel
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
Falk Tannhäuser Guest
|
Posted: Wed Apr 21, 2004 4:25 pm Post subject: Re: const_cast problem |
|
|
Daniel Schüle wrote:
| Quote: | g++ und icc liefern die gleiche Ausgabe
10
100
10
200
allerings ist diese nicht definiert durch den Standard
(meineswissens)
was spucken die anderen Compiler weiss ich nciht
vielleicht sagt das jemand, wäre interessant
Ich habe bloß g++. Es reicht, "a" 'static' oder |
global zu machen, damit es tatsächlich spu(c)kt:
10
100
Signal 11
(unter Windows / Cygwin gcc 3.3.1) oder
10
100
Memory fault
(unter Linux / gcc 2.95.4 oder 3.0.4)
Versuche ich dasselbe mit "b", habe ich stets
10
100
10
200
Offenbar werden statische oder globale 'const'-Variablen in einem
Nur-Lese-Segment abgelegt, während 'volatile'-Variablen (ob const
oder nicht) in einem beschreibbaren Segment landen.
Hieraus auf das Verhalten von Kombinationen anderer Prozessoren,
OS, Compiler (Hersteller / Versionen), Optionen, Mondphasen,
Euro/Dollar-Kurse etc. schließen zu wollen, halte ich für äußerst
gewagt.
MfG
Falk
--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|