Ist das zu unveränderlich zu const?

8

Grundsätzlich habe ich folgende Situation. Hinweis: void* wird verwendet, um beliebige Daten zu bezeichnen, sie wird in einer realen Anwendung stark typisiert.

%Vor%

Bei der Suche nach der Korrektheit der Korrektheit wird intermediate_buffer_ niemals offengelegt, so dass es der Definition für die Verwendung einer mutable -Variable entspricht. Wenn ich diesen Puffer nie wieder verwendet habe, oder ich vor der Verwendung der zwischengespeicherten Werte nach gleichen input_data gesucht habe, wäre das das Ende der Geschichte, aber wegen der Wiederverwendung_zwischen habe ich das Gefühl, dass ich ihn halb enthülle, also bin ich mir nicht sicher, ob oder nicht das Folgende ist sinnvoll.

%Vor%

Gedanken?

    
IdeaHat 26.03.2014, 15:56
quelle

7 Antworten

6

Ich denke, das ist eine missbräuchliche Verwendung von mutable . Meiner Erfahrung nach wird mutable für zusätzliche private Membervariablen verwendet, die ihrer Natur nach nicht als const deklariert werden können, aber die "konzeptuelle Konsistenz" der öffentlichen Schnittstelle nicht verändern.

Nehmen Sie zum Beispiel eine Mutex-Member-Variable und einen 'Thread-sicheren Getter':

%Vor%

Der Hauptpunkt hier ist, dass die deklarierten Daten mutable (in diesem Fall der Wächter) sich ändern (es ist gesperrt und entsperrt), aber dies hat keine Auswirkung auf die Konsistenz aus der Benutzerperspektive. Trotz des veränderbaren Mutex können Sie die const Datenelementvariable immer noch nicht ändern, und der Compiler erzwingt dies .

In Ihrem Fall wollen Sie wirklich, dass der intermediate_buffer const ist, aber Sie sagen dem Compiler ausdrücklich es ist nicht , indem Sie es als veränderbar deklarieren. Das Ergebnis ist, dass Sie die Daten ändern können und der Compiler nichts dagegen tun kann .

Siehst du den Unterschied?

Wenn Sie wirklich wollen, dass die Schnittstelle der const-Vereinbarung entspricht, machen Sie sie über etwas wie folgt explizit:

%Vor%

Jetzt ist die Aufgabe wirklich für den Benutzer und wird vom Compiler durchgesetzt, unabhängig davon, was die Kommentare sagen und ohne Verwendung von mutable. Wenn sie wissen, dass sich input_data geändert hat, müssen sie ein neues erstellen, vorzugsweise const.

    
Andy 21.04.2014, 22:46
quelle
4

Anstatt das Zwischenobjekt im const-Objekt auszublenden, setzen Sie es frei und lassen Sie foo und bar eine Kopie zurückgeben. Sie machen es sehr explizit, dass das Zwischenobjekt geteilt wird, und bieten eine neue Fähigkeit, mehr als einen zur Hand zu haben. Wenn Sie die Implementierungsdetails ausblenden möchten, können Sie eine leere Klasse verfügbar machen und das Zwischenobjekt zu einem Kind dieser Basisklasse machen.

%Vor%     
Mark Ransom 21.04.2014 23:25
quelle
1

Um Ihre Frage direkt zu beantworten. Wenn die Funktion foo const ist, sollte der Aufruf zu keiner Zeit das Ergebnis der nächsten Operationen ändern.

zum Beispiel:

%Vor%

sollte genau das gleiche Ergebnis liefern wie (ohne Leistungsunterschiede)

%Vor%

Da foo const ist, erwarten die Benutzer, dass das Ergebnis gleich ist. Wenn dies der Fall ist, ist es sinnvoll, den Puffer mutable zu machen. Sonst ist es wahrscheinlich falsch.

Hoffe, das hilft

    
tiridactil 22.04.2014 00:17
quelle
0

Haftungsausschluss: Ich bin nicht für die Verwendung von void* mit meiner Antwort, ich hoffe, dass dies nur zu Demonstrationszwecken war und dass Sie nicht wirklich selbst verwenden müssen.

Wenn viele Berechnungen bei der Wiederverwendung der gleichen Eingabedaten gespeichert werden können, dann machen Sie input_data zu einer Mitgliedsvariablen.

%Vor%

Dies ist nur ein Überblick, ohne weitere Details darüber, was input_data , intermediate_buffer und something sind oder wie sie verwendet oder geteilt werden, werden viele Details fehlen. Ich würde definitiv die Zeiger von der Implementierung fallenlassen und std::vector benutzen. Dies gilt insbesondere für input_data , wo Sie eine Kopie des übergebenen Puffers speichern möchten. Überlegen Sie:

%Vor%

Sie erhalten wahrscheinlich ein falsches Ergebnis, wenn Sie ein nicht übereinstimmendes Paar input_data/intermediate_buffer verwenden.

Beachten Sie auch, dass Sie, wenn Sie input_data für foo und bar nicht benötigen, die void* input_data aus der Klasse löschen können, aber den Konstruktor und den Setter, die darauf verweisen, behalten.

    
SirGuy 18.04.2014 14:10
quelle
0

Ich würde sagen, dass Ihre Verwendung von mutable sinnvoll ist - aber das ist falsch und möglicherweise gefährlich. Wenn du eine Funktion const machst, muss es genau das sein.

Stellen Sie sich vor, Sie verwenden Ihre Klasse in einem Multithread-Programm mit mehreren Threads, die auf derselben Instanz der Klasse arbeiten - zum Beispiel:

%Vor%

Da thread2 eine Funktion const aufruft, sollte sie keinen Einfluss auf die Ausgabe von bar von thread1 haben - aber wenn das Timing richtig ist (oder falsch!), wird es - und wegen Aus diesen Gründen würde ich sagen, dass es falsch ist, in diesem Fall mutable zu verwenden, um foo const zu erstellen, selbst wenn Sie nur die Klasse aus einem einzigen Thread verwenden.

    
sonicwave 18.04.2014 15:21
quelle
0

Da Sie input_data nicht auf Äquivalenz überprüfen können, könnten Sie vielleicht einen kryptografischen Hash davon nehmen und diesen für den Vergleich verwenden. Dies würde das reuse_intermediate Flag überflüssig machen.

    
Mark Ransom 21.04.2014 23:03
quelle
0

mutable wird verwendet, um die Const-ness einer Variablen oder eines Datenmembers zu überschreiben. Beispiel:

%Vor%

Im obigen Beispiel könnte die Funktion foo a.m ändern, obwohl Sie eine const-Referenz übergeben haben. In Ihrem Beispiel glaube ich nicht, dass Sie veränderbar verwenden müssen - es kann zu sehr schlechten Designs führen - da Sie in diesen Puffer schreiben werden.

    
Pandrei 23.04.2014 15:10
quelle

Tags und Links