Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

CodingCat

1x Contest-Sieger

Beiträge: 420

Beruf: Student (KIT)

  • Private Nachricht senden

11

07.09.2014, 13:15


Guten Tag zusammen,
ich habe eine kurze Frage bezüglich const-correctness. Ich habe eine Klasse Texture die intern ein Zeiger auf eine LPDIRECT3DTEXTURE9 Resource hat. Außerdem habe ich eine Methode

C-/C++-Quelltext

1
LPDIRECT3DTEXTURE9 getInterface();

die genau diesen Zeiger zurückgibt. Kann ich diese Methode als const deklarieren? Bei Aufruf dieser Methode wird der logische Status des Texture-Objekts nicht verändert, jedoch ist es mit dem zurückgegebenen Pointer sehr leicht möglich den "Inhalt" der Klasse maßgeblich zu verändern.

Viele Grüße

newby

Kann: Ja. Sollte? Depends. Die Idee hinter const-Korrektheit ist es, Veränderung transitiv (also durch viele Zugriffs- oder Aufrufebenen hindurch) durch den Compiler prüfbar zu verbieten. Nehmen wir also an, deine getInterface()-Methode wäre Teil einer Texture-Klasse, und eine beliebige Funktion in deinem Code nähme einen Zeiger auf ein konstantes Texture-Objekt entgegen. Dann gibt diese Funktion durch den Parametertyp const Texture* oder const Texture& ihren Aufrufern zu verstehen, dass sie das übergebene Texturobjekt nicht verändern wird. Zu diesem Texturobjekt gehört nun aber auch die enthaltene DirectX-Textur, und es wäre für den gutgläubigen Aufrufer sicher ein erschütternder Vertrauensbruch, wenn diese Funktion trotz ihres Versprechens anfinge, die enthaltene DirectX-Textur zu verändern. Da die DirectX-Textur logisch zweifelsohne ein integraler Bestandteil des Texturobjekts ist, ist die intuitive Erwartungshaltung bei Garantie der Unveränderlichkeit des Textur-Objekts ganz klar, dass auch die DirectX-Textur unverändert bleibt. Lektion Nr. 1: Die Anwendung von const ist eine Frage der Bedeutung, und nicht der (Un)veränderlichkeit von Zeigerbits.

Welche praktische Auswirkung hat das auf das Beispiel? Wenn der zurückgegebene Zeiger auf die Textur tatsächlich nur zum Lesezugriff GEDACHT ist, wäre die Antwort in einer perfekten Welt: const IDirect3DTexture9* GetInterface() const. Heißt übersetzt: Ein konstantes Texturobjekt gibt einen Zeiger auf eine konstante DirectX-Textur zurück. Jetzt könnte es natürlich sein, dass du für nicht-konstante Texturobjekte auch Zugriff auf eine nichtkonstante DirectX-Textur willst. In diesem Fall bräuchtest du eine zusätzliche Methode IDirect3DTexture9* GetInterface(), welche sich dann nur für nichtkonstante Texturobjekte aufrufen ließe, dafür aber einen Zeiger auf eine nichtkonstante DirectX-Textur zurückgäbe.

Und jetzt die schlechte Nachricht: Das alles funktioniert für DirectX nicht. DirectX selbst ist überhaupt nicht const-korrekt, das heißt es gibt keine einzige const-Methode im ganzen DirectX-SDK und folglich lässt sich mit einem Zeiger auf eine konstante DirectX-Textur überhaupt gar nichts anfangen. An dieser Stelle geht die Transitivität unweigerlich kaputt und du hast gar keine andere Wahl, als immer Zeiger auf veränderliche Objekte zurückzugeben und zu hoffen, dass deine Aufrufer das Richtige tun. Die tatsächliche praktische Antwort ist also: Du solltest deine Methode const machen, damit sie auch für konstante Texturobjekte aufgerufen werden kann, und du musst hoffen, dass Aufrufer mit konstanten Texturobjekten damit keinen Unfug treiben. Lektion Nr. 2: const-Korrektheit ist in der Realwelt oftmals schwer durchzusetzen.


Es gibt da zwei ARten von const Correctness. Das eine ist die die der Compiler erkennen kann und das andere ein Fall wie dieser hier. Über Referenzen oder Zeiger wird etwas zurück gegeben wodurch der Zustand doch verändert werden kann. Was von beidem du willst ist deine Sache. Wobei ich denke dass es sinnvoll ist nur mit const zu arbeiten wenn das Objekt wirklich konstant ist. Bin aber auch nicht mehr wirklich drin da.

Was du eigentlich sagen solltest, ist: Es gibt zwei Arten von Constness. Bitweise 'physikalische' Constness wird vom Compiler standardmäßig transitiv weitergegeben, d.h. in einer Struktur

C-/C++-Quelltext

1
2
3
4
5
6
struct Struct
{
   int i;
   float f;
   Objekt* o;
};

sind für konstante Struct-Instanzen i, f und o-Zeiger automatisch konstant, d.h. die Typen sind const int i, const float f und Objekt *const o. Achtung, der letzte Typ ist NICHT const Objekt* o, sondern Objekt *const o, d.h. der Zeiger ist unveränderlich, nicht aber das Objekt auf das er zeigt, siehe TGGCs Antwort.

Logische Constness hingegen habe ich gerade eben im Texturbeispiel erklärt: Wenn das referenzierte Objekt o ein Bestandteil der Struct-Instanz darstellt, wollen wir eigentlich nur Zugriffe auf das konstante Objekt zulassen - um das zu erzwingen, muss o privat sein und wir brauchen ggf. wie beschrieben zwei Methoden um vollständigen const-korrekten Zugriff zu erlauben.

Das eigentliche Problem ist, dass diese Methode die Kapselung des Objekts aufbricht. Constness kann dann natürlich auch nicht mehr garantiert werden.

Die Methode bricht in der Tat ggf. Kapselung auf, das hat aber keine unmittelbare Auswirkung auf const-Korrektheit. Das eigentliche Problem ist wie erklärt, dass DirectX nicht const-korrekt ist.

Wenn man es genau nimmt, ist "const" mehr ein Hinweis und nicht wirklich strikt. Das ist einer der Gründe warum C# kein const kennt. Also wenn du "const" dran schreibst, muss der Nutzer hoffen, dass auch "const" drinne ist.
Ich persönlich habe lieber einen schwachen Hinweis als garkeine Information.

Jein, const ist so strikt wie es die jeweilige Schnittstelle umsetzt, aber nicht "nur ein Hinweis". Die von einem Modul im const-Fall gegebenen Garantien müssen in der Tat explizit angegeben werden, weil Implementierungsdetails ggf. die Tragweite logischer const-Korrektheit einschränken; in diesem Rahmen ist const-Korrektheit ein Hilfsmittel des Compilers, die Einhaltung auf atomarer Ebene gegebenen Garantien in den höheren Ebenen durchzusetzen.

Was mich generell wundert: Wieso sollte man einen Zeiger auf ein Interface ändern wollen? Wenn das passiert ist doch ziemlich was schief gelaufen.
Ansonsten mach es doch so:

C-/C++-Quelltext

1
const IDirect3DTexture9* const GetInterface() const {return _interface;}

Da kann nichts mehr schiefgehen.

Kompletter Unfug, siehe Erklärung und TGGCs Antwort.
alphanew.net (last updated 2011-06-26) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »CodingCat« (07.09.2014, 13:22)