Welchen Wert hat const void * über void *?

7

Gibt es in C ++ einen Wert bei der Verwendung von const void * für einen Argumenttyp für eine Funktion über einem void * ? Da ein void * undurchsichtig ist, besteht das Risiko einer Änderung, außer wenn der Benutzer reinterpret_cast tut, in diesem Fall könnten sie ebenfalls const_cast auf einem const void * tun, und kauft man wirklich alles? Ich frage, weil ich eine Utility-Template-Klasse für Shared-Pointer verwendet habe, die eine Spezialisierung auf void bietet, um void & issue zu vermeiden, aber keine Spezialisierung für const void , und ich frage mich, ob das nur ein Versehen war oder nie benötigt werden?

    
WilliamKF 09.07.2012, 15:42
quelle

6 Antworten

9

Es bietet den gleichen Vorteil, den const für andere Zeigertypen bietet: Sie können das, worauf gezeigt wird, nur ändern, wenn Sie const -ness explizit wegwerfen. In Schnittstellen ist const void* ein Zeichen für Client-Code, dass alles, was Sie übergeben, gelesen, aber nicht geschrieben werden kann. Zum Beispiel wird std::memcpy als

deklariert %Vor%

was signalisiert, dass es src lesen und in dest schreiben wird. Natürlich, wenn es wirklich in C ++ (möglich, aber nicht wahrscheinlich) implementiert wurde, muss es beide Zeiger auf andere Typen umwandeln.

Wenn Sie der Meinung sind, dass Ihnen das "nichts kauft", dann hat das const -Schlüsselwort per se offensichtlich keinen Wert.

    
Fred Foo 09.07.2012, 15:46
quelle
4

memcpy benötigt zwei Zeigerparameter, einen void* und den anderen const void* . Der zweite Parameter kann implizit von einem const char* (oder einem anderen Pointer-zu-Const-Objekttyp) -Argument konvertiert werden, während der erste nicht.

Das Fehlen der impliziten Konvertierung ist der Wert - es zwingt den Benutzer dazu, const in dem (unwahrscheinlichen) Ereignis, das er will, absichtlich wegzuwerfen, anstatt es versehentlich zu verwerfen.

Dann müsste der Programmierer in einer Implementierung von memcpy oder einer ähnlichen Funktion const_cast oder C-style-cast den const void* -Parameter eingeben, bevor er versucht, seinen Verweis zu modifizieren. Sie könnten static_cast den nichtkonstanten Parameter eingeben und seinen Verweis ändern. Die Art der Besetzung, die du schreiben musst, um hoffentlich zu sagen, sagt dir etwas darüber, ob das, was du tust, sinnvoll ist.

Ich denke, wenn Ihre shared_ptr Hilfsfunktionen void speziell behandeln müssen, dann müssten sie alle cv-qualifizierten void speziell behandeln. Das sind vier Fälle: void , const void , volatile void , const volatile void . Aber wenn Benutzer der Funktionen in der Vergangenheit versucht haben, es auf eine shared_ptr<void> , und beschwerte sich, dass es nicht funktioniert hat, aber noch nie probiert es auf eine shared_ptr<const void> , dann ist das Problem möglicherweise nicht aufgetreten.

Vielleicht ist shared_ptr<void> bereits ungewöhnlich genug, dass es nicht aufgetaucht ist. Vielleicht tendiert die Art von Person, die shared_ptr<void> benutzt, dazu, cv-Qualifier wegzuwerfen, mit der Begründung, dass, wenn jemand irgendwann den richtigen Typ wiederherstellt, er auch die richtigen Qualifiers wiederherstellt.

Wenn Sie daran denken - funktioniert shared_ptr<const void> überhaupt, oder benötigt der Code in shared_ptr , der den Deleter aufruft, eine implizite Konvertierung von T* nach void* ? Ich erinnere mich nicht, ob ich jemals ein shared_ptr<const T> benutzt habe.

    
Steve Jessop 09.07.2012 15:47
quelle
3

Vergessen Sie nicht den "Dokumentationswert" von const . Obwohl jemand es immer wegwerfen kann, dient das const dazu, die ursprüngliche Absicht anzuzeigen, dass das Ding, auf das gezeigt wird, nicht über den Zeiger geändert werden sollte. const_cast (und reinterpret_cast ) sollten immer mit Vorsicht verwendet werden und sollten dem Programmierer eine Pause einräumen, wenn / wenn es notwendig ist.

    
Turix 09.07.2012 15:46
quelle
2

Nun ja, es gibt (einige) die gleichen Vorteile, die const immer hat: es dokumentiert die Tatsache, dass der Inhalt nicht mutiert werden soll.

Stellen Sie sich den folgenden Code vor:

%Vor%

Dieser Aufruf wird nur kompiliert, wenn das Funktionsargument als void const* deklariert wurde, andernfalls würde der Client eine const_cast benötigen, um die Konstanz wegzuwerfen. Natürlich möchten wir nicht, dass der Klient diese Unannehmlichkeiten hat, und wir wollen auch nicht, dass sie über ihre Daten lügen (indem sie Konstanz wegwerfen).

    
Konrad Rudolph 09.07.2012 15:48
quelle
1

Es ist immer noch von Vorteil, den Code "selbst zu dokumentieren".

%Vor% Mit

ohne Kommentar können Sie sehen, dass die angegebenen Daten nicht geändert werden.

Beachten Sie außerdem, dass eine Funktion sowohl eine const als auch eine const_cast ausführen müsste, um diese reinterpret_cast promise zu brechen.

    
aschepler 09.07.2012 15:48
quelle
1

Wie bei allen Verwendungen von const dient es zwei Zwecken. Bei der Implementierung der Funktion wird es dem Compiler helfen, Fehlbedienungen zu entdecken, die, wie Sie erwähnen, mit Hilfe von const_cast (oder einer C-artigen Umwandlung) erzwungen und zum Schweigen gebracht werden können.

Aber const dient einem zweiten Zweck, es bietet die Verheißung, dass das Objekt nicht verändert wird, und ermöglicht es so Benutzern, Zeiger auf const Objekte zu übergeben (unter der Annahme, dass Sie Ihr Versprechen halten) breitere Nutzung Ihrer Funktion. Dies kann an diesem einfachen Beispiel gesehen werden:

%Vor%     
quelle