Unveränderbare C ++ - Containerklasse

9

Angenommen, ich habe eine C ++ - Klasse, Container , die einige Elemente vom Typ Element enthält. Aus verschiedenen Gründen ist es ineffizient, unerwünscht, unnötig, unpraktisch und / oder unmöglich (1), den Inhalt nach der Konstruktion zu modifizieren oder zu ersetzen. Etwas in der Art von const std::list<const Element> (2).

Container kann viele Anforderungen der STL-Konzepte "Container" und "Sequenz" erfüllen. Es kann die verschiedenen Typen wie value_type , reference usw. bereitstellen. Es kann einen Standardkonstruktor, einen Kopierkonstruktor, einen const_iterator Typ, begin() const , end() const , size , empty , alle Vergleichsoperatoren und möglicherweise einige von rbegin() const , rend() const , front() , back() , operator[]() und at() .

Jedoch kann Container nicht liefern insert , erase , clear , push_front , push_back , nicht-konstant front , nicht-konstant back , nicht-konstant operator[] oder nicht-const at mit der erwarteten Semantik. So scheint es, dass Container sich nicht als "Sequenz" qualifizieren kann. Ferner kann Container nicht operator= und swap bereitstellen und kann keinen iterator -Typ bereitstellen, der auf ein nicht-konstantes Element zeigt. Es kann also nicht einmal als "Container" bezeichnet werden.

Gibt es ein weniger fähiges STL-Konzept, das Container erfüllt? Gibt es einen "Nur-Lese-Container" oder einen "unveränderlichen Container"?

Wenn Container kein definiertes Konformitätsniveau erfüllt, gibt es einen Wert in Teilkonformität? Ist es irreführend, dass es wie ein "Container" aussieht, wenn es sich nicht qualifiziert? Gibt es eine prägnante, eindeutige Möglichkeit, die Konformität zu dokumentieren, damit ich die konforme Semantik nicht explizit dokumentieren muss? Und ähnlich, eine Möglichkeit, es zu dokumentieren, so dass zukünftige Benutzer wissen, dass sie den Read-only-generischen Code nutzen können, aber nicht erwarten, dass mutierende Algorithmen funktionieren.

Was bekomme ich, wenn ich das Problem lockere, so dass Container Assignable ist (aber seine Elemente nicht sind)? An diesem Punkt sind operator= und swap möglich, aber Dereferenzierung von iterator gibt immer noch const Element zurück. Ist Container jetzt ein "Container"?

const std::list<T> hat ungefähr dieselbe Schnittstelle wie Container . Bedeutet das, dass es weder ein "Container" noch eine "Sequenz" ist?

Fußnote (1) Ich habe Anwendungsfälle, die dieses ganze Spektrum abdecken. Ich habe eine Möchtegern-Container-Klasse, die einige schreibgeschützte Daten anpasst, also muss sie unveränderlich sein. Ich habe einen Möchtegern-Container, der bei Bedarf eigene Inhalte generiert, also veränderbar ist, aber Sie können Elemente nicht so ersetzen, wie es die STL erfordert. Ich habe noch einen anderen Möchtegern-Container, der seine Elemente so speichert, dass insert() so langsam wird, dass es niemals nützlich wäre. Und schließlich habe ich eine Zeichenfolge, die Text in UTF-8 speichert, während eine Codepunkt-orientierte Schnittstelle freigelegt wird; eine veränderbare Implementierung ist möglich, aber völlig unnötig.

Fußnote (2) Dies ist nur zur Veranschaulichung. Ich bin mir ziemlich sicher, dass std::list einen zuweisbaren Elementtyp benötigt.

    
George Compton 29.03.2011, 21:00
quelle

2 Antworten

2

Die STL definiert keine niedrigeren Konzepte; vor allem, weil die Idee von const normalerweise auf einer Per-Iterator- oder Per-Reference-Ebene ausgedrückt wird, nicht auf einer Pro-Klassen-Ebene.

Sie sollten iterator nicht mit unerwarteten Semantiken versehen, sondern nur const_iterator . Dies ermöglicht Client-Code an der logischsten Stelle (mit der am besten lesbaren Fehlermeldung) zu versagen, wenn sie einen Fehler machen.

Möglicherweise ist der einfachste Weg das zu tun, es zu kapseln und alle nicht-const-Aliase zu verhindern.

%Vor%

Nun weiß jeder Client-Code genau, was er mit dem Rückgabewert von Resultsnada tun kann, der eine Mutation erfordert.

    
Puppy 29.03.2011 21:47
quelle
1

Solange Ihr Objekt einen Const_iterator bereitstellen kann, muss es nichts anderes haben. Es sollte ziemlich einfach sein, dies in Ihrer Containerklasse zu implementieren.

(Sehen Sie sich ggf. die Bibliothek Boost.Iterators an; sie enthält die Klassen iterator_facade und iterator_adaptor, die Sie bei den Details unterstützen)

    
sehe 29.03.2011 21:34
quelle

Tags und Links