Const entfernen - const_cast

Ein const_cast wird wie folgt aufgebaut

const_cast< TypVonObject_ohne_Const >( object )

Zurückgegeben wird das übergebene Objekt, der allerdings im Datentyp den Const-Correctness-Qualifizierer verloren hat.

Ein Const-Cast ist eine legitimierte Notlösung. Gelegentlich stößt man auf alte Funktionen, die zwar noch benötigt werden, jedoch zu einer Zeit geschrieben wurden, als Const-Correctness für die meisten Entwickler noch ein Fremdwort war.

fehlendes Const bei Parametern

Hat man Beispielsweise eine Funktion in einer alten Library wie int myStrLen( char * ) und möchte diese nun verwenden, um die Länge eines const char * zu ermitteln:

#include <stdio.h>
 
int myStrLen( char * str )
{
  int l = 0;
  while( *str++ )
	  l++;
 
  return l;
}
 
int main(int argc, char **argv)
{
	char const * text = "Hallo Welt";
 
	int length = myStrLen( text );
 
	printf( "Der Text ist %d Zeichen lang\n", length );
 
	return 0;
}

Dieser Quelltext liefert folgende Fehler:

error: invalid conversion from `const char*' to `char*'
error:   initializing argument 1 of `int myStrLen(char*)'

Hier wäre sicherlich der richtige Weg, die Funktion myStrLen anzupassen, aber nehmen wir an, wir wissen, dass sie das Objekt nicht verändert, doch wir haben den Quelltext nicht vorliegen, weil sie in einer gekauften Library liegt. Um dieses Programm zu kompilieren müssten wir nun entweder eine Kopie des Strings erstellen, was Zeitaufwendig wäre. Um dies zu vermeiden - wenn wir denn wissen, dass die Funktion die übergebenen Parameter nicht verändert - wurde const_cast erfunden.

Unser Problem mit der myStrLen-Funktion lässt sich mit einem const_cast, wie folgt lösen:

int main(int argc, char **argv)
{
	char const * text = "Hallo Welt";
 
	int length = myStrLen( const_cast< char * >( text ) );
 
	printf( "Der Text ist %d Zeichen lang\n", length );
 
	return 0;
}

const_cast muss den gleichen Datentyp zurückgegeben, dass das Objekt besitzt, lediglich der const-Qualifizierer darf fehlen. Es ist also nicht möglich gleichzeitig const und den Datentyp zu verändern. In dem Fall sollte const_cast mit einem static_cast kombiniert werden, auch wenn ein C-Style-Cast kürzer wäre. Nur mit dieser Ausführlichkeit lässt sich aus dem Quelltext herauslesen, was genau gemeint ist und die Hässlichkeit des Quelltextes an der Stelle markiert deutlich, dass hier etwas passiert, dem man Aufmerksamkeit schenken sollte, wenn man einen Fehler sucht.

fehlendes Const bei Const-Methoden

Es lassen sich so auch Methoden von Objekten aufrufen, die nicht als Const gekennzeichnet sind. Die Wahrscheinlichkeit, hier Fehler in ein Programm einzubauen steigt allerdings deutlich, denn wäre die Methode für einen const-Zugriff geeignet hätte ein guter Entwickler sie entsprechend markiert!

#include <stdio.h>
 
class Value
{
  int a;
 
  public:
 
  Value( int value ) : a( value ) {} 
  int add( int b ) { return a+b; } 
};
 
int main(int argc, char **argv)
{
  Value const v( 1 );  // Konstantes Objekt
 
  int result = v.add( 2 );
 
  printf( "Ergebnis: %d\n", result );
 
  return 0;
}

wird mit der Meldung

error: passing `const Value' as `this' argument of `int Value::add(int)' discards qualifiers

belohnt. (siehe auch hier)

Wenn wir sicher sein können, dass das Objekt nicht verändert wird und es nicht möglich ist, die Klasse Value zu verbessern, dann hilft der const_cast, in dem wir uns eine Referenz auf das Objekt ohne den const-Qualifizierer geben lassen:

  int result = const_cast< Value & >( v ).add( 2 );

Die bessere Lösung

Besser wäre jedoch die Klasse Value zu verbessern und die Methode add zu einer Const-Methode zu ändern:

int add( int b ) const { return a+b; }

Fazit

Hier zeigt sich sehr schön, dass ein Cast in der Regel nur einen Fehler an anderer Stelle kaschiert. Entsprechend selten, möglichst gar nicht, sollten Castings in den eigenen Quelltexten auftreten.

Grundsätzlich lässt sich das Problem an der Überschrift ablesen: const fehlt beim Datentyp des Parameters einer Funktion oder Methode oder es fehlt das const bei der Methodendeklaration. Ein const_cast ist immer nur eine Notlösung, wenn man sich mit einer Library beschäftigten muss, die man nicht ändern kann. Ansonsten sollte man sich besser um die Ursache kümmern, statt Symptome zu behandeln.