Eine Klasse mit const Datenelementen in einem Vektor verwenden

8

Bei einer Klasse wie dieser:

%Vor%

Ist es möglich, diese Klasse in einen Vektor zu setzen? Wenn ich es versuche, sagt mir mein Compiler, dass es den Standardzuweisungsoperator nicht verwenden kann. Ich versuche, mein eigenes zu schreiben, aber googlen herum erzählt mir, dass es unmöglich ist, einen Zuweisungsoperator für eine Klasse mit const Datenelementen zu schreiben. Ein Post, den ich gefunden habe, sagte: "Wenn du [das Datenelement] const hast, bedeutet das, dass du nicht willst, dass eine Zuweisung überhaupt stattfindet." Das macht Sinn. Ich habe eine Klasse mit const Datenmembern geschrieben, und ich habe nie beabsichtigt, eine Zuweisung darauf zu verwenden, aber anscheinend brauche ich eine Zuweisung, um sie in einen Vektor zu setzen. Gibt es einen Weg, der const-Korrektheit noch erhält?

    
Max 26.05.2010, 22:20
quelle

4 Antworten

7
  

Ich habe eine Klasse mit const Datenmembern geschrieben, und ich habe nie beabsichtigt, eine Zuweisung dafür zu verwenden, aber anscheinend brauche ich eine Zuweisung, um sie in einen Vektor zu schreiben. Gibt es einen Weg, der const-Korrektheit noch erhält?

Sie müssen fragen, ob die folgende Bedingung noch gilt

%Vor%

Wenn diese Einschränkung nicht für a und b vom Typ Foo gilt (Sie müssen die Semantik dessen definieren, was "äquivalent" bedeutet!), dann können Sie Foo nicht in einen Standard setzen Container. Zum Beispiel kann auto_ptr nicht in Standardcontainer eingegeben werden, da es diese Anforderung verletzt.

Wenn Sie über Ihren Typ sagen können, dass er diese Einschränkung erfüllt (wenn zum Beispiel das Element const in keiner Weise an dem Wert Ihres Objekts teilnimmt, aber dann erwägt, es zu einem statischen Datenelement zu machen), dann können Sie das tun Schreiben Sie Ihren eigenen Zuweisungsoperator

%Vor%

Aber denken Sie zweimal nach! . Für mich sieht es so aus, dass Ihr Typ die Einschränkung nicht erfüllt!

    
Johannes Schaub - litb 26.05.2010 22:25
quelle
3

Verwenden Sie einen Vektor von Zeigern std::vector<Foo *> . Wenn Sie die Mühe vermeiden wollen, nach sich selbst aufzuräumen, verwenden Sie boost::ptr_vector .

    
Jesse Beder 26.05.2010 22:23
quelle
1

Bearbeiten : Mein erster Stich während meiner Kaffeepause, static const int a; wird nicht für den Anwendungsfall funktionieren, den das OP im Sinn hat, was die ersten Kommentare bestätigen, also schreibe ich neu und erweitere es meine Antwort.

Meistens, wenn ich ein Element einer Klasse konstant machen will, ist es eine Konstante, deren Wert für alle Zeiten und für alle Instanzen der Klasse konstant ist. In diesem Fall verwende ich eine statische const-Variable:

%Vor%

Diese müssen nicht zwischen Instanzen kopiert werden. Wenn dies zutrifft, würde das das Problem lösen. Leider hat das OP darauf hingewiesen, dass dies für den Fall, den das OP im Auge hat, nicht funktionieren wird.

Wenn Sie einen schreibgeschützten Wert erstellen möchten, den Clients nicht ändern können, können Sie ihn zu einer privaten Membervariable machen und sie nur über eine Const-Getter-Methode als einen anderen Post auf diesem Objekt verfügbar machen thread zeigt an:

%Vor%

Der Unterschied zwischen diesem und

%Vor%

ist:

  • Die const int gibt Ihnen die Gewissheit, dass nicht einmal die Implementierung der Klasse in der Lage ist, während der Lebensdauer des Objekts mit dem Wert von a zu arbeiten. Dies bedeutet, dass die Zuweisung zu Recht nicht funktioniert, da dies versuchen würde, den Wert von a zu ändern, nachdem das Objekt erstellt wurde. (Das ist der Grund, warum man eine benutzerdefinierte operator=() schreibt, die die Kopie von a überspringt, ist wahrscheinlich eine schlechte Idee, was das Design betrifft.)
  • Der Zugriff ist anders - Sie müssen einen Getter durchlaufen, anstatt direkt auf das Mitglied zuzugreifen.

Wenn ich in der Praxis zwischen den beiden wähle, verwende ich schreibgeschützte Mitglieder. Dies bedeutet wahrscheinlich, dass Sie den Wert eines Objekts durch den Wert eines anderen Objekts ersetzen können, ohne die Semantik zu verletzen. Lass uns sehen, wie es in deinem Fall funktionieren würde.

Betrachten Sie Ihr Gitterobjekt mit einer Breite und Höhe. Wenn Sie den Vektor zum ersten Mal erstellen und sagen, dass Sie mit vector::reserve() einen anfänglichen Speicherplatz reservieren, wird Ihr Vektor mit initial default-initialisierten (d. H. Leeren) Grids gefüllt. Wenn Sie eine bestimmte Position im Vektor zuweisen oder ein Raster auf das Ende des Vektors schieben, ersetzen Sie den Wert des Objekts an dieser Position durch ein Raster, das tatsächliche Elemente enthält. Aber du kannst damit einverstanden sein! Wenn der Grund, dass Breite und Höhe konstant sein sollten, wirklich die Konsistenz zwischen Breite und Höhe und dem Rest des Inhalts Ihres Grid-Objekts ist, und Sie haben sichergestellt, dass es egal ist, ob width und height werden ersetzt, bevor oder nachdem andere Elemente von Grid ersetzt wurden, dann sollte diese Zuweisung sicher sein, da am Ende der Zuweisung der gesamte Inhalt der Instanz ersetzt wurde und Sie wieder in einem konsistenten Zustand sind. (Wenn das Fehlen der Atomarität der Standardzuweisung ein Problem war, könnten Sie dies wahrscheinlich umgehen, indem Sie Ihren eigenen Zuweisungsoperator implementieren, der einen Kopierkonstruktor und eine Operation swap() verwendet.)

Zusammenfassend kann man sagen, dass man mit Read-Only-Gettern die Objekte in einem Vektor oder einem Container mit einer Wertesemantik verwenden kann. Es liegt jedoch an Ihnen, sicherzustellen, dass keine der internen Operationen von Grid (oder die Operationen von Grid-Freunden) diese Konsistenz verletzen, da der Compiler die Breite und Höhe für Sie nicht sperren wird. Dies gilt auch für die Standardkonstruktion, den Kopieraufbau und die Zuweisung.

    
Owen S. 26.05.2010 22:25
quelle
0

Ich überlege, das Datenelement nicht-const zu machen, sondern privat und nur zugänglich durch eine get-Funktion, so:

%Vor%

Ist das so gut wie const? Hat es irgendwelche Nachteile?

    
Max 26.05.2010 22:48
quelle