Unterschied zwischen unveränderlich und const

28

Ich habe die Begriffe oft gesehen immutableund constsynonym verwendet. Nach meiner (geringen) Erfahrung unterscheiden sich die beiden jedoch stark in dem Vertrag, den sie im Code schließen:

Unveränderlich macht der Vertrag, dass sich dieses Objekt überhaupt nicht ändert (zB Python-Tupel, Java-Strings).

Const schließt den Vertrag, dass im Gültigkeitsbereich dieser Variablen keine Änderungen vorgenommen werden (keine Zusicherung darüber, was andere Threads für das Objekt tun könnten, auf das in diesem Zeitraum verwiesen wird, z. B. das Schlüsselwort C / C ++).

Offensichtlich sind die beiden nicht gleichwertig, es sei denn, die Sprache ist ein Singlethread (PHP) oder sie verfügt über ein lineares oder eindeutiges Typisierungssystem (Clean, Mercury, ATS).

Erstens, ist mein Verständnis dieser beiden Konzepte korrekt?

Zweitens, wenn es einen Unterschied gibt, warum werden sie fast ausschließlich austauschbar verwendet?

K.Steff
quelle
1
constgibt es nicht in jeder Sprache und Veränderlichkeit und Unveränderlichkeit gibt es nicht in jeder Sprache, so dass diese Sprache nicht agonistisch ist. Es ist nur sprachspezifisch , wo diese Konzepte zutreffen.
2
Verwandte, empfohlene Lektüre: Arten der Unveränderlichkeit (einige C # -Beispiele, aber weitgehend sprachunabhängig). Jemand gibt Eric Lippert eine Medaille.

Antworten:

14

Ich werde mit C ++ sprechen, wo dieser Unterschied am relevantesten ist.

Wie Sie richtig bemerken, bedeutet unveränderlich , dass sich ein Objekt nach seiner Erstellung überhaupt nicht ändern kann. Diese Erstellung kann natürlich zur Laufzeit erfolgen, dh ein constObjekt ist nicht unbedingt eine Konstante zur Kompilierungszeit. In C ++ ist ein Objekt unveränderlich, wenn (1) und entweder (2) oder (3) erfüllt sind:

  1. Es wurden keine Mitglieder deklariert mutable, die durch constMitgliederfunktionen mutiert sind

  2. Es ist deklariert const

  3. constMitgliedsfunktionen werden nicht const_castzum Entfernen von constQualifikationen verwendet, um Mitglieder zu mutieren

Sie können jedoch auch Zugriffsmodifikatoren in Betracht ziehen: Wenn eine Operation eine Instanz intern mutiert, sich jedoch nicht auf den über die öffentliche Schnittstelle beobachtbaren Zustand der Instanz auswirkt, ist das Objekt „logisch unveränderlich“.

Daher bietet C ++ die Tools, die zum Erstellen unveränderlicher Objekte erforderlich sind. Wie die meisten anderen Tools in C ++ sind die Tools jedoch nur minimal ausreichend und erfordern Sorgfalt, um sie tatsächlich zu verwenden. Der Status einer Instanz ist nicht notwendigerweise auf die Instanzmitgliedsvariablen beschränkt - da C ++ keine Möglichkeit bietet, referenzielle Transparenz zu erzwingen, kann er auch den globalen Status oder den Klassenstatus enthalten.

consthat auch eine andere Funktion in C ++: Referenzen und Zeiger zu qualifizieren. Eine constReferenz kann sich auf ein Nichtobjekt beziehen const. Es ist legal (obwohl im Allgemeinen nicht notwendig oder ratsam), const_castein Objekt durch einen constVerweis zu mutieren , wenn und nur wenn dieses Objekt als nicht deklariert wird const:

int        i = 4;         // Non-const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Legal.

Und natürlich ist es undefiniertes Verhalten, ein constObjekt zu mutieren :

const int  i = 4;         // const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Illegal.
Jon Purdy
quelle
19

Wenn Sie für Java sprechen, wobei das Schlüsselwort "final" für "const" steht, sollten Sie Folgendes berücksichtigen:

final Person someone = new Person();

Dies bedeutet, dass someoneNIEMALS auf ein anderes Personenobjekt verwiesen werden darf. Sie können jedoch die Details der überwiesenen Person ändern. Z.Bsomeone.setMonthlySalary(10000);

Wenn es sich someonejedoch um ein "unveränderliches" Objekt handelt, ist eine der folgenden setMonthlySalary Bedingungen erfüllt : (a) Sie hätten keine Methode mit dem Namen (b) Der Aufruf von setMonthlySalary würde immer eine Ausnahme auslösen, zUnsupportedOperationException

rationale Revolution
quelle
10

Unveränderliche Objekte sind Objekte, deren Status sich nach dem Erstellen nicht ändert. Beispielsweise;

string prefix = "Pre";
string postfix = "Post";
string myComplexStr = prefix + postfix;

In diesem Beispiel ist das myComplexStr-Objekt unveränderlich, aber nicht konstant, da sein Wert berechnet wird. Und es ist unveränderlich, weil es ein String ist, eine statische Längeneigenschaft hat und sich nicht ändern kann.

Const-Objekte werden im Allgemeinen verwendet, um einige reale Konstanten zu identifizieren, deren Werte vor dem Kompilieren bekannt sind, z. B. Pi, "USA", "StackOverflow.com", Portnummern usw.

Aus dieser Perspektive unterscheidet sich Const von unveränderlichen Objekten, da ihre Werte nicht vom Programm berechnet werden.

Wenn Sie jedoch über das Schlüsselwort "const" in C ++ sprechen, können Sie sagen, dass "const" zum Erstellen unveränderlicher Objekte verwendet wird.

Mert Akcakaya
quelle
1
const in C ++ erstellt keine unveränderlichen Objekte, es ist nur eine Zugriffsebene.
Klaim
Können Sie erklären, warum "const double pi = 3.14" nicht unveränderlich ist?
Mert Akcakaya
Nun, es kommt darauf an, wo es ist. Sagen wir, ich mache: "double * p_pi = const_cast <double *> (& pi; * p_pi = 42;" beispielsweise. Wenn sich pi dann im globalen Raum oder Namespace befindet, erhalte ich einen Segmentierungsfehler, aber ich glaube, es handelt sich nicht um einen bestimmten Fehler, sondern um ein undefiniertes Verhalten. Wenn pi ein Mitglied eines Objekts ist, das zur Laufzeit verfügbar ist und nicht statisch ist, erhalte ich pi == 42. Sogar die Verwendung von mutable ist verfügbar, da const in C ++ die Zugriffsstufe, die Semantik und nicht die Unveränderlichkeit von Daten betrifft ist in C ++ fast unmöglich zu erreichen. Sie können es nur "simulieren". const ist nicht unveränderlich.
Klaim
1
@Klaim Das Mutieren eines solchen constVerhaltens ist undefiniert, egal wo es zugeordnet ist, IIRC. Undefiniertes Verhalten ist schlimmer als ein bestimmter Fehler, der garantiert auftritt. Es bedeutet, dass Sie C ++ nicht mehr verwenden - C ++ bietet keine Möglichkeit, einen constWert zu ändern (außer mutablenatürlich Mitglieder, aber das ist nicht Ihr Punkt), was C ++ betrifft, können Sie dies nicht tun. Welche spezifischen Implementierungen dies zulassen, ist eine ganz andere Sache (und ich wette, wenn Sie mit Optimierungen kompilieren, hat der Stunt, den Sie gezogen haben, keinen Einfluss auf spätere Ausdrücke, pida er ersetzt wurde).
"const in C ++ erstellt keine unveränderlichen Objekte" ist immer noch falsch, weil es immer noch globale Konstanten erstellt, wie Sie in Ihrer eigenen Antwort angegeben haben. Das Schlüsselwort ist auf einer bestimmten Ebene natürlich semantisch, andernfalls können Sie die Spannung einer Speicherzelle und den Wert eines unveränderlichen Objekts immer manuell ändern, wenn Sie unbedingt undefinierte Verhaltensweisen verwenden möchten.
Mert Akcakaya
8

Erstens, ist mein Verständnis dieser beiden Konzepte korrekt?

Ja, aber Ihre zweite Frage zeigt, dass Sie diese Unterschiede nicht verstehen.

Zweitens, wenn es einen Unterschied gibt, warum werden sie fast ausschließlich austauschbar verwendet?

constin C ++ wird nur für die Zugriffsebene verwendet (es bedeutet "schreibgeschützt") , nicht für die Unveränderlichkeit. Dies bedeutet, dass der Zugriff von den Daten völlig getrennt ist. Beispielsweise könnten Sie einige Daten manipulieren und sie dann über eine konstante Referenz verfügbar machen. Der Zugriff ist schreibgeschützt, aber die Daten selbst, da alle Daten veränderbar sind.

const garantiert nur Zugriffsbeschränkungen, während Unveränderlichkeit (wie zum Beispiel in D) wirklich keine Möglichkeit bedeutet, die Daten in irgendeinem Stadium der Lebensdauer des Objekts zu ändern .

Jetzt können Sie die Unveränderlichkeit in C ++ simulieren, indem Sie sicherstellen, dass auf einige Daten nur mit const zugegriffen werden kann, und sicherstellen, dass sie initialisiert und dann nicht mehr berührt werden. Dies ist jedoch keine Garantie, da Sprachen wie D Ihnen dies ermöglichen, wenn Sie Ihre Daten als unveränderlich markieren. Die Sprache stellt sicher, dass es überhaupt nicht möglich ist, Operationen durchzuführen, die diese Daten ändern, während Sie in C ++ die Daten möglicherweise noch durch Const Casting und Mutability ändern können, falls dies wirklich notwendig ist.

Am Ende ist es überhaupt nicht dasselbe, wie es überhaupt nicht die gleichen Garantien bietet.

Klaim
quelle
3

Apropos JavaScript, die Schlüsselwörter constundObject.freeze

constgilt für bindungenvariables . Es wird eine unveränderliche Bindung erstellt, der Sie keinen neuen Wert zuweisen können.

Object.freezeArbeitet mit Objektwerten. Es macht ein Objekt unveränderlich . Sie können nämlich seine Eigenschaften nicht ändern.

zangw
quelle
0

In C ++ sind sie gleich. Obwohl Sie ein constObjekt ändern können, wenn Sie dessen Speicherort und Betriebssystemberechtigung zum Schreiben in diesen Speicher haben.

Martin Beckett
quelle
1
Eigentlich ist das ein Argument dagegen , dass sie gleich sind: C ++ hat einfach keine unveränderliche Schlüsselwort- oder Sprachunterstützung. Außerdem gehe ich davon aus, dass der Programmierer die Sprache auf vernünftige Weise verwendet: Ansonsten hat auch const absolut keinen Wert.
K.Steff
1
@ K.Steff - vielleicht besser gesagt, es gibt keine zusätzliche Unveränderlichkeit in C ++, die nicht von const bereitgestellt wird
Martin Beckett
Absolut genau :)
K.Steff
In C ++ sind sie überhaupt nicht gleich. const ist "schreibgeschützt". Dies bedeutet nicht, dass die Daten unveränderlich sind. Sie können es in C ++ die meiste Zeit umgehen.
Klaim
0

In C, C ++ und verwandten Sprachen gibt es auch einen Unterschied zwischen einem Objekt, das const ist, und Ihrer Referenz oder Ihrem Zeiger auf das Objekt, das eine konstante Referenz ist.

Wenn Sie versuchen, ein konstantes Objekt zu ändern, tritt ein undefiniertes Verhalten auf. (Sie können versuchen , ein konstantes Objekt zu ändern, indem Sie beispielsweise seine Adresse übernehmen, die Adresse in einen Nicht-Konstanten-Zeiger umwandeln und dann diesen Nicht-Konstanten-Zeiger verwenden, um das Objekt zu ändern.)

Der konstante Zeiger oder Verweis auf der anderen Seite teilt dem Compiler lediglich mit, dass Sie diesen Zeiger oder Verweis nicht zum Ändern des Objekts verwenden können. Sie können den Zeiger oder die Referenz umwandeln und versuchen, das Objekt zu ändern. Wenn das Objekt selbst konstant war, werden schlimme Dinge passieren. Wenn das Objekt nicht konstant war, ändert es sich. Dies kann natürlich die Benutzer Ihres Codes verwirren und möglicherweise Fehler verursachen.

Wenn Sie in C ein Zeichenfolgenliteral wie "Hallo" verwenden, sind die fünf Zeichen und die nachfolgenden Nullbytes tatsächlich konstant, aber Sie erhalten einen Nicht-Konstanten-Zeiger. Sehr schlechte Idee, diesen Nicht-Konstanten-Zeiger zu verwenden, um das Objekt zu ändern.

In C können Sie einen Zeiger "const restrict" haben. Das heißt, das Objekt, auf das gezeigt wird, ist vorübergehend konstant. Wenn das Objekt auf irgendeine Weise geändert wird, während sich der Zeiger "const restrict" im Gültigkeitsbereich befindet, tritt undefiniertes Verhalten auf. Dies ist stärker als ein const-Zeiger, der nur verhindert, dass Sie ein Objekt über diesen Zeiger ändern.

gnasher729
quelle