Ist jedes Objekt in C ++ veränderbar, wenn nicht anders angegeben?
In Python und Javascript kann ich keine Zeichenfolgen, Tupel oder Unicodes ändern. Ich habe mich gefragt, ob es in C ++ etwas gibt, das unveränderlich ist oder jedes Objekt veränderbar ist, und ich muss das Typqualifikationsmerkmal verwenden const
, um es unveränderlich zu machen.
Antworten:
Die Unveränderlichkeit ist seit einiger Zeit bekannt. Python, Java und C ++ haben unterschiedliche Speichermodelle, die direkte Vergleiche erschweren. Der Autor des Artikels, den Sie ursprünglich zitiert haben , scheint C ++ nicht zu kennen.
Wie in Python, Java und den meisten Sprachen mit mehreren Paradigmen ermöglichen C und C ++ standardmäßig die Veränderbarkeit. Dies ist, was Programmierer normalerweise wollen: Wenn ich eine
String x
Variable habe, möchte ich in der Lage sein, einen neuen Wert zuzuweisenx = "foo"
.Das const-System in C und C ++ ermöglicht eine Menge nuancierter Unveränderlichkeit, die in Python, Java und sogar Scala fehlt. Wenn eine C ++ - Funktion a
const std::string&
oder a benötigtconst char*
, verspricht sie (und der Compiler stellt bis zu einem gewissen Grad sicher), dass diese Funktion den Inhalt dieser Zeichenfolge nicht ändert (kann!). Bei einem gegebenen const-Objekt können wir nur Methoden dieses Objekts aufrufen, die auch als const markiert sind. Wenn eine C ++ - Klasse nur öffentliche Mitglieder hatconst
, ist das Objekt effektiv unveränderlich.Dies ist jedoch manchmal verwirrend, da in C und C ++ Objekte Speicherorte sind und Variablen Namen für Speicherorte sind. Im Gegensatz dazu sind Variablen in Python und Java Namen für Zeiger auf Objekte. In einer Sprache mit Referenzsemantik
x = y
bedeutet dies, dass x auf dasselbe Objekt wie y zeigt. Da wir nur Zeiger kopieren, ist dies mit unveränderlichen Objekten möglich. In einer Sprache mit Wertesemantik wie C ++ bedeutet dies "Aktualisieren des Inhalts vonx
mit dem Inhalt vony
". Wenn daher eine Neuzuweisung einer Variablen in C oder C ++ gewünscht wird, hat die Variable möglicherweise keinen const-Typ. Um dies mit unveränderlichen Objekten zu tun, müssten wir explizit einen Zeiger verwenden.Dass Java und Python unveränderliche Zeichenfolgenobjekte verwenden, ist eine grundlegende Entwurfsentscheidung, hängt jedoch nicht direkt mit den Vorteilen der Unveränderlichkeit in einer Multithreading-Umgebung zusammen. Ein Grund dafür ist, dass Zeichenfolgenliterale im Quellcode zusammengefasst werden können, wodurch die Anzahl der Objekte verringert wird. Dies ist auch in C / C ++ möglich. In C ++ hat das Literal
"foo"
den Typconst char[4]
(das 4. Zeichen ist das Beenden'\0'
). Ein weiterer Grund ist, dass Einträge in Sets und Schlüssel in Diktaten / Karten nicht geändert werden dürfen. Da Zeichenfolgen häufig als Diktatschlüssel verwendet werden (die meisten Python-Objekte sind Diktatschlüssel), wird durch die Unveränderlichkeit eine häufige Fehlerquelle beseitigt. In Java ist das Java-Sicherheitsmodell ein weiterer Grund für unveränderliche Zeichenfolgen. All diese Gründe haben nichts mit Multithreading zu tun.Wenn Java mit Blick auf Unveränderlichkeit erstellt worden wäre, hätte die Sprache ganz anders ausgesehen. Obwohl es stark von C ++ inspiriert ist, haben die Designer versucht, eine viel einfachere Sprache zu erstellen. Die Beseitigung von const ist ein solcher Schritt. Das Java-Äquivalent zu einer C ++ - Konstantenreferenz ist ein Adapter oder Dekorator, der alle Mutationsmethoden als implementiert
throws new NotImplementedException()
und nicht mutierende Methodenaufrufe an die eigentliche Sammlung weiterleitet. Die Tatsache, dass die java.util-Auflistung alle Schnittstellen impliziert, ist ein klares Zeichen dafür, dass sie nicht nach einer unveränderlichen Sprache strebten.Die Lösung, die Java zur Lösung von Parallelitätsproblemen vorschlug, war nicht Unveränderlichkeit, sondern allgegenwärtiges Sperren. Jedes einzelne Objekt enthält einen Mutex, der für
synchronized
Blöcke oder ganze Methoden verwendet werden kann. Wie sich herausstellt, ist das nicht gut für die Leistung, skaliert nicht sehr gut und ist ziemlich fehleranfällig - Sie müssen sich immer noch mit veränderlichen globalen Zuständen auseinandersetzen.quelle
mut
Schlüsselwort erfordert und für die der Compiler unnötige Veränderlichkeit kennzeichnet) stützen meine Hypothese: In Rust haben Sie viel mehrlet
Bindungen als Sielet mut
.for x in 1..10
nichtlet mut
definiert wird, aber offensichtlich eine gewisse Veränderlichkeit erfordert (nur auf Schleifenebene, nicht innerhalb des Schleifenkörpers).const T o = [&]{T o; o.init(...); return o;}();
… yay für APIs, die nicht unter Berücksichtigung der Unveränderlichkeit entwickelt wurden.Fast. Die Sprache selbst behandelt alles als wandelbar es sei denn , Sie verwenden
const
, aber es ist immer noch möglich , unveränderliche Objekte zu bauen , ohne den Compiler zu sagen sie unveränderlich sind, indem man einfach nicht , einen Weg zu mutieren sie.Nehmen Sie zum Beispiel diese Klasse:
Instanzen von
MyClass
sind unveränderlich, weil es keine Möglichkeit gibt, sie zu mutieren - aber nirgends im Code wird tatsächlich angegeben, dass sie unveränderlich sind. (Dies ist die gleiche Art und Weise, wie Instanzen der Java-String
Klasse unveränderlich sind.)quelle
delete
Stellt der Kopierzuweisungsoperator hier auch sicher, dass man nicht über die Verschiebungszuweisung op aus einer rWertreferenz zuweisen kann?value
const zu deklarieren undgetValue()
eine const-Funktion zu deklarieren .Nein, es gibt eine Ausnahme: Lambdas und die von ihnen erfassten Objekte sind standardmäßig unveränderlich:
Anstatt also hinzuzufügen
const
, um es unveränderlichmutable
zu machen, fügen Sie hinzu , um es nicht zu machenconst
.quelle