Ein Beispiel dafür, wo ein const-Zeiger hoch anwendbar ist, kann auf diese Weise demonstriert werden. Angenommen, Sie haben eine Klasse mit einem dynamischen Array darin und möchten dem Benutzer den Zugriff auf das Array übergeben, ohne ihm jedoch die Rechte zum Ändern des Zeigers zu erteilen. Erwägen:
#include <new>
#include <string.h>
class TestA
{
private:
char *Array;
public:
TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
~TestA(){if(Array != NULL){ delete [] Array;} }
char * const GetArray(){ return Array; }
};
int main()
{
TestA Temp;
printf("%s\n",Temp.GetArray());
Temp.GetArray()[0] = ' '; //You can still modify the chars in the array, user has access
Temp.GetArray()[1] = ' ';
printf("%s\n",Temp.GetArray());
}
Welches produziert:
Eingabedaten
setzen Daten
Aber wenn wir das versuchen:
int main()
{
TestA Temp;
printf("%s\n",Temp.GetArray());
Temp.GetArray()[0] = ' ';
Temp.GetArray()[1] = ' ';
printf("%s\n",Temp.GetArray());
Temp.GetArray() = NULL; //Bwuahahahaa attempt to set it to null
}
Wir bekommen:
Fehler: lWert als linker Operand der Zuordnung erforderlich // Drat erneut vereitelt!
So klar können wir den Inhalt des Arrays ändern, aber nicht den Zeiger des Arrays. Gut, wenn Sie sicherstellen möchten, dass der Zeiger einen konsistenten Status hat, wenn Sie ihn an den Benutzer zurückgeben. Es gibt jedoch einen Haken:
int main()
{
TestA Temp;
printf("%s\n",Temp.GetArray());
Temp.GetArray()[0] = ' ';
Temp.GetArray()[1] = ' ';
printf("%s\n",Temp.GetArray());
delete [] Temp.GetArray(); //Bwuahaha this actually works!
}
Wir können die Speicherreferenz des Zeigers weiterhin löschen, auch wenn wir den Zeiger selbst nicht ändern können.
Wenn Sie also möchten, dass die Speicherreferenz immer auf etwas verweist (IE wird niemals geändert, ähnlich wie eine Referenz derzeit funktioniert), ist sie in hohem Maße anwendbar. Wenn Sie möchten, dass der Benutzer vollen Zugriff hat und ihn ändert, ist non-const genau das Richtige für Sie.
Bearbeiten:
Nachdem er den Kommentar okorz001 bemerkt hat, dass er nicht zugewiesen werden kann, weil GetArray () ein Operand mit dem richtigen Wert ist, ist sein Kommentar völlig korrekt, aber das oben Gesagte gilt immer noch, wenn Sie einen Verweis auf den Zeiger zurückgeben (ich nehme an, ich habe GetArray angenommen) unter Bezugnahme auf eine Referenz), zum Beispiel:
class TestA
{
private:
char *Array;
public:
TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
~TestA(){if(Array != NULL){ delete [] Array;} }
char * const &GetArray(){ return Array; } //Note & reference operator
char * &GetNonConstArray(){ return Array; } //Note non-const
};
int main()
{
TestA Temp;
Temp.GetArray() = NULL; //Returns error
Temp.GetNonConstArray() = NULL; //Returns no error
}
Wird im ersten zurückkehren, was zu einem Fehler führt:
Fehler: Zuweisung des schreibgeschützten Speicherorts 'Temp.TestA :: GetArray ()'
Aber die zweite wird trotz möglicher Konsequenzen für die Unterseite fröhlich auftreten.
Offensichtlich wird die Frage aufgeworfen, warum Sie einen Verweis auf einen Zeiger zurückgeben möchten. Es gibt seltene Fälle, in denen Sie dem betreffenden Originalzeiger Speicher (oder Daten) direkt zuweisen müssen (z. B. Erstellen eines eigenen malloc / free- oder new / free-Frontends). In diesen Fällen handelt es sich jedoch um eine nicht konstante Referenz . Ein Verweis auf einen const-Zeiger Ich bin nicht auf eine Situation gestoßen, die dies rechtfertigen würde (es sei denn, es handelt sich möglicherweise um deklarierte const-Referenzvariablen anstatt um Rückgabetypen?).
Überlegen Sie, ob wir eine Funktion haben, die einen konstanten Zeiger verwendet (im Gegensatz zu einer, die dies nicht tut):
class TestA
{
private:
char *Array;
public:
TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
~TestA(){if(Array != NULL){ delete [] Array;} }
char * const &GetArray(){ return Array; }
void ModifyArrayConst(char * const Data)
{
Data[1]; //This is okay, this refers to Data[1]
Data--; //Produces an error. Don't want to Decrement that.
printf("Const: %c\n",Data[1]);
}
void ModifyArrayNonConst(char * Data)
{
Data--; //Argh noo what are you doing?!
Data[1]; //This is actually the same as 'Data[0]' because it's relative to Data's position
printf("NonConst: %c\n",Data[1]);
}
};
int main()
{
TestA Temp;
Temp.ModifyArrayNonConst("ABCD");
Temp.ModifyArrayConst("ABCD");
}
Der Fehler in der const erzeugt also folgende Meldung:
Fehler: Dekrement des schreibgeschützten Parameters 'Daten'
Was gut ist, da wir das wahrscheinlich nicht wollen, es sei denn, wir wollen die in den Kommentaren angegebenen Probleme verursachen. Wenn wir das Dekrement in der const-Funktion herausarbeiten, geschieht Folgendes:
NonConst: A
Const: B.
Obwohl A 'Daten [1]' ist, wird es eindeutig als 'Daten [0]' behandelt, da der NonConst-Zeiger die Dekrementierungsoperation zuließ. Wenn die const implementiert ist, wie eine andere Person schreibt, erkennen wir den potenziellen Fehler, bevor er auftritt.
Eine andere wichtige Überlegung ist, dass ein const-Zeiger als Pseudoreferenz verwendet werden kann, indem das Objekt, auf das die Referenz zeigt, nicht geändert werden kann (man fragt sich, ob es vielleicht so implementiert wurde). Erwägen:
int main()
{
int A = 10;
int * const B = &A;
*B = 20; //This is permitted
printf("%d\n",A);
B = NULL; //This produces an error
}
Beim Kompilieren wird der folgende Fehler ausgegeben:
Fehler: Zuweisung der schreibgeschützten Variablen 'B'
Was wahrscheinlich eine schlechte Sache ist, wenn ein ständiger Verweis auf A gewünscht wurde. Wenn dies auskommentiert B = NULL
ist, lässt der Compiler uns gerne ändern *B
und daher A. Dies scheint bei Ints möglicherweise nicht nützlich zu sein. Überlegen Sie jedoch, ob Sie eine einzelne Haltung einer grafischen Anwendung hatten, in der Sie einen nicht modifizierbaren Zeiger wollten, der darauf verweist und den Sie übergeben könnten um.
Die Verwendung ist variabel (entschuldigen Sie das unbeabsichtigte Wortspiel), aber bei richtiger Verwendung ist es ein weiteres Werkzeug in der Box, das Sie bei der Programmierung unterstützt.