const und non-const Versionen von * static * -Memberfunktionen

8

Ich habe zwei Versionen der gleichen statischen Member-Funktion: man nimmt einen Zeiger auf einen const-Parameter und einen Zeiger auf einen nicht-konstanten Parameter. Ich möchte Code-Duplizierung vermeiden.
Nachdem ich einige Stack-Überlauf-Fragen gelesen hatte (diese waren alle über nicht statische Member-Funktionen), kam ich auf folgendes:

%Vor%

(Ich weiß, dass das Jonglieren mit Zeigern generell eine schlechte Idee ist, aber ich implementiere eine Datenstruktur.)

Ich habe Code in libstdc ++ gefunden, der so aussieht:
HINWEIS: Dies sind keine Mitgliedsfunktionen

%Vor%

In der ersten Annäherung ist der Code in einer Funktion, die einen Zeiger zum const Parameter nimmt.
In der zweiten Annäherung ist der Code in einer Funktion, die einen Zeiger-zu-nicht-const Parameter nimmt Welcher Ansatz sollte generell verwendet werden? Sind beide richtig?

    
Xack 04.01.2016, 17:53
quelle

2 Antworten

1

Die wichtigste Regel ist, dass eine Interface-Funktion (öffentliche Methode, eine andere freie Funktion als eine in einem Detail-Namespace usw.) die Konstanz ihrer Eingabe nicht wegwerfen sollte. Scott Meyer war einer der Ersten, der über die Vermeidung von Duplizierung mit const_cast sprach. Hier ist ein typisches Beispiel ( Wie entferne ich die Code-Duplizierung zwischen ähnlichen const- und nicht-const-Member-Funktionen? ):

%Vor%

};

Dies bezieht sich eher auf Instanzmethoden als auf statische / freie Funktionen, aber das Prinzip ist dasselbe. Sie bemerken, dass die nicht-const-Version const hinzufügt, um die andere Methode aufzurufen (bei einer Instanzmethode ist der this -Zeiger die Eingabe). Es wirft dann am Ende Konstanz ab; das ist sicher, weil es weiß, dass die ursprüngliche Eingabe nicht const war.

Dies andersherum umzusetzen wäre extrem gefährlich. Wenn Sie die weg -Konstante eines Funktionsparameters, den Sie erhalten, umwandeln, gehen Sie in UB ein großes Risiko ein, wenn das an Sie übergebene Objekt tatsächlich const ist. Nämlich, wenn Sie irgendwelche Methoden aufrufen, die das Objekt tatsächlich mutieren (was aus Versehen sehr leicht zu tun ist, nachdem Sie die Konstanz weggeworfen haben), können Sie leicht UB bekommen:

  

C ++ Standard, Abschnitt § 5.2.11 / 7 [const cast]

     

[Hinweis: Abhängig vom Typ des Objekts, eine Schreiboperation durch den Zeiger, lvalue oder Zeiger auf Datenelement resultierend aus a   const_cast, das ein const-Qualifikationsmerkmal ausgibt, kann zu undefinierten Ergebnissen führen   Verhalten. -Hinweis]

Es ist nicht so schlimm in privaten Methoden / Implementierungsfunktionen, weil Sie vielleicht genau kontrollieren, wie / wann es aufgerufen wurde, aber warum so? Es ist gefährlicher, keinen Nutzen zu haben.

Vom Konzept her ist es oft der Fall, dass Sie, wenn Sie eine konstante und nicht konstante Version der gleichen Funktion haben, nur interne Referenzen des Objekts übergeben ( vector::operator[] ist ein kanonisches Beispiel) und nichts wirklich mutieren , was bedeutet, dass es sicher sein wird, wie auch immer du es schreibst. Aber es ist noch gefährlicher, die Konstanz der Eingabe wegzuwerfen; Auch wenn es unwahrscheinlich ist, dass Sie es selbst vermasseln, stellen Sie sich eine Teameinstellung vor, bei der Sie falsch herum schreiben und es funktioniert, und dann ändert jemand die Implementierung, um etwas zu verändern, was Ihnen UB gibt.

Zusammenfassend kann es in vielen Fällen keinen praktischen Unterschied machen, aber es gibt einen korrekten Weg, der strikter ist als die Alternative: add constness zum Eingang und entfernen constness von der Ausgabe .

    
Nir Friedman 04.01.2016 20:15
quelle
0

Ich habe deine erste Version eigentlich nie zuvor gesehen, daher ist es aus meiner Erfahrung die häufigere Redewendung.

Die erste Version scheint mir korrekt zu sein, während die zweite Version zu undefiniertem Verhalten führen kann, wenn (A) ein tatsächliches const-Objekt an die Funktion übergeben wird und (B) die long code an dieses Objekt schreibt. Vorausgesetzt, dass der Compiler Ihnen im ersten Fall sagt, wenn Sie versuchen, auf das Objekt zu schreiben, würde ich Option 2 niemals so empfehlen, wie sie ist. Sie könnten eine eigenständige Funktion in Erwägung ziehen, die const jedoch akzeptiert / zurückgibt.

    
Mark B 05.01.2016 17:02
quelle

Tags und Links