Rachus: Wann ist ein const_cast angebracht?

Beitrag lesen

Hallo,

Erste Frage, warum?

Ich wollte mir eine Klasse schreiben, die mir das Hantieren mit Iteratoren der unordered_multimap versteckt und dabei gleich noch etwas optimieren.

Der Schlüssel selbst liegt in einer anderen Datenstruktur (einer std::list; damit wird bei mehreren Werten eines Schlüssels der Schlüssel trotzdem garantiert nur einmal gespeichert). Nun sieht eine Funktion beispielsweise so aus (ist hoffentlich selbsterklärend):

template<class Key, class Value, class Hash, class Equals>
inline const bool
UM_Wrapper<Key, Value, Hash, Equals>::key_exists(const Key& key) const
{
return data.find(&key) != data.end();
}

Kannst du das vielleicht mal wörtlich beschreiben? Die Syntax finde ich als Java Gewöhnter nicht so intuitiv. Also: was hast du für Datenstrukturen und für Klassen und wer soll was warum womit machen.

UM_Wrapper ist meine Klasse, die um die Hashtabelle (std::unordered_multimap) der Standardbibliothek herumgebaut wurde. Zusätzlich verwende ich noch eine std::list, die die Schlüssel speichert. Die Hashtabelle selber nutzt zum Indexen Zeiger auf die, in der Liste liegenden, Schlüssel und als Werte Paare, die einen Iterator auf den Schlüssel und den eigentlich Wert zu speichern. (Den Iterator habe ich da eingebaut, da ich nicht wusste, wie ich meiner Hasher-/Equaler-Funktionsklassen klarmache, dass das fast das gleiche ist).
Nun ist es so, dass bei einem einfachen key_exists eine konstante Referenz (in Java wohl mit final vergleichbar) übergeben wird. Konstant, da das zur sauberen Schnittstelle gehört (und man liest im Internet ja genügend über C++ Const Correctness). Die Methode find von der unordered_multimap erwartet auch eine konstante Referenz auf ein Objekt des Schlüsseltyps (Key*). Nur sichert mir sie nicht mehr zu, dass auch der Bereich, auf den der Zeiger zeigt (durch &key hole ich mir ja einen Zeiger, da dieser Operator die Speicheradresse zurückgibt) auch konstant bleibt. Diese Zusicherung habe ich allerdings dem Aufrufer meiner Methode gegeben. Daher kompiliert sie auch ohne Cast nicht.
(Hier hoffe ich, dass ich die Compilerfehler auch richtig gedeutet habe… Sie sind nicht immer ganz leicht verständlich.)

Generell sind casts böse. Nämlich deshalb, weil dadurch Fehler nur noch zur Laufzeit festgestellt werden können; das bedeutet, die Verantwortung verlagert sich vom Compiler auf dich - und das willst du nicht.

Und deswegen wollte ich in diesem Falle erfragen, ob hier eine Situation vorliegt, in der ein Cast sinnvoll ist, oder ob ich die Klasse lieber mal über den Haufen werfen sollte.

Grüße,

Rachus