const_iterator vs. iterator



  • Hallo Zusammen, ich habe eine Klasse geschrieben, die iterierbar ist. Die Iteratoren sind vom Typ 'input_iterator'. Es kann also gelesen, jedoch nicht geschrieben werden. In den Kontainerklassen der 'stl' findet man sowohl 'iterator' als auch 'const_iterator', hier kann sowohl geschrieben als auch gelesen werden. Jetzt stellt sich mir die Frage, wie ich meinen Iterator nun benennen soll. Nur 'iterator' oder 'const_iterator'? Es handelt sich offensichtlich um einen konstanten Iterator der keinen Schreibzugriff zulässt. Dies spricht für 'const_iterator'. Allerdings gibt es keine zwei verschiedenen Typen von Iteratoren in meiner Klasse. Macht hier eine explizite Qualifizierung meines Operators als const überhaupt Sinn?

    MFG

    Martin


  • Mod

    iterator und const_iterator unterscheiden sich nicht notwendigerweise dadurch, dass durch sie Objekte verändert werden können oder nicht, sondern in ihrem Ursprung. Ein const_iterator kann von einem konstanten (Container-)Objekt erzeuget werden, der nicht-const iterator hingegen stammt von einem modifizierbaren Container.

    Operieren deine Iteratoren also grundsätzlich ohne die zugrundeliegende Datenstruktur zu verändern, so solltest du einen const_iterator definieren und dann entweder
    - iterator als typedef anbieten, oder
    - iterator als wrapper um const_iterator gestalten (damit sind dann gewisse logische Fehler bei der Benutzung vermeidebar, die zum Beispiel auf einer unsinnigen Konvertierung const_iterator->iterator beruhen)

    Verändern die Iteratoren bei der Benutzung hingegen das Containerobjekt in nach aussen beobachtbarer Weisen, können sie keine const_iteratoren sein, selbst wenn das Verändern von Elementen über den Iterator nicht möglich ist.


  • Mod

    (damit sind dann gewisse logische Fehler bei der Benutzung vermeidebar, die zum Beispiel auf einer unsinnigen Konvertierung const_iterator->iterator beruhen)

    Bspw.?

    Nur 'iterator' oder 'const_iterator'?

    Beides, und iterator auf const_iterator typedef 'n. So findet man es zumindest in gängigen std::set Implementierungen - dort sind die Elemente ebenfalls nicht modifizierbar, jedoch wird selbstverständlich ein einheitliches Interface bewahrt.


  • Mod

    Arcoth schrieb:

    (damit sind dann gewisse logische Fehler bei der Benutzung vermeidebar, die zum Beispiel auf einer unsinnigen Konvertierung const_iterator->iterator beruhen)

    Bspw.?

    container c;
    container::const_iterator x = c.begin();
    container::iterator y = x; // ?
    

    Arcoth schrieb:

    Nur 'iterator' oder 'const_iterator'?

    Beides, und iterator auf const_iterator typedef 'n. So findet man es zumindest in gängigen std::set Implementierungen - dort sind die Elemente ebenfalls nicht modifizierbar, jedoch wird selbstverständlich ein einheitliches Interface bewahrt.

    M.A.n. eine ungünstige Lösung. Leider sagt der Standard dazu: unspezifiziert.
    Wenn die Typen gleich sein dürfen, kann man nicht darauf basierend überladen.
    Den Spareffekt, der sich ergibt, indem ein einfaches typedef statt einer vollen Klassendefinition verwendet wird, halte ich für unerheblich - erst recht aus Sicht des Nutzers.


  • Mod

    camper schrieb:

    container c;
    container::const_iterator x = c.begin();
    container::iterator y = x; // ?
    

    Offensichtlich ist container nicht dependent. :p Daher sollte der Nutzer mit der Semantik vertraut sein.

    Wenn die Typen gleich sein dürfen, kann man nicht darauf basierend überladen.

    Guter Punkt. Das ist ein Argument, vor allem wenn man e.g. Klassentemplates schreibt die den Containertyp als Argument nehmen und intern solche Überladungen deklarieren..

    Wobei mir eigentlich kein gutes Beispiel einfällt, denn wenn man zwischen der cv-qualification eines Containers unterscheiden möchte, ist er entweder

    - ein Member, in welchem Fall man einfach durch entsprechende cv-qualification der Memberfunktion überladen kann, oder
    - ein Argument, jedoch kann man dann per cv-qualification der Referenz überladen, die diesen Container nimmt.

    Wenn man nur Iteratoren haben möchte, warum hat man sich dann überhaupt anfangs auf diese spezifischen Iteratoren beschränkt? Warum den Typ nicht templateisieren?

    Ich habe auch noch nie Code gesehen der Dispatching anhand von iterator / const_iterator vornimmt.



  • Sehr hilfreiche Antworten. Die Arbeit den const_iterator zu ummanteln werde ich mir jetzt nicht machen. Ein Typedef sollte für meinen Fall ausreichen sein. 👍


Anmelden zum Antworten