Пример того, где указатель const очень применим, может быть продемонстрирован таким образом. Предположим, у вас есть класс с динамическим массивом внутри, и вы хотите передать пользователю доступ к массиву, но не предоставляя им права на изменение указателя. Рассматривать:
#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());
}
Который производит:
Входные данные
положить данные
Но если мы попробуем это:
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
}
Мы получили:
error: lvalue требуется в качестве левого операнда присваивания // Drat снова сорвался!
Ясно, что мы можем изменить содержимое массива, но не указатель массива. Хорошо, если вы хотите убедиться, что указатель имеет согласованное состояние при передаче его обратно пользователю. Но есть одна загвоздка:
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!
}
Мы все еще можем удалить ссылку памяти указателя, даже если мы не можем изменить сам указатель.
Поэтому, если вы хотите, чтобы ссылка на память всегда указывала на что-то (IE никогда не изменялся, подобно тому, как ссылка работает в настоящее время), тогда она очень применима. Если вы хотите, чтобы пользователь имел полный доступ и изменил его, тогда non-const для вас.
Редактировать:
Обратите внимание на комментарий okorz001 о невозможности назначения из-за того, что GetArray () является операндом с правильным значением, его комментарий полностью верен, но вышеприведенное применимо, если вы должны вернуть ссылку на указатель (я полагаю, я предполагал, что GetArray был ссылаясь на ссылку), например:
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
}
Вернется в первом, что приведет к ошибке:
ошибка: назначение места только для чтения 'Temp.TestA :: GetArray ()'
Но второе произойдет весело, несмотря на потенциальные последствия на дне.
Очевидно, возникнет вопрос: «Почему вы хотите вернуть ссылку на указатель»? В редких случаях вам нужно назначить память (или данные) непосредственно исходному указателю (например, создать свой собственный malloc / free или new / free front-end), но в этих случаях это неконстантная ссылка , Ссылка на константный указатель Я не сталкивался с ситуацией, которая оправдывала бы это (разве может быть, как объявленные константные ссылочные переменные, а не возвращаемые типы?).
Рассмотрим, есть ли у нас функция, которая принимает константный указатель (по сравнению с той, которая этого не делает):
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");
}
Ошибка в const выдает таким образом сообщение:
ошибка: уменьшение параметра «Данные» только для чтения
Это хорошо, так как мы, вероятно, не хотим этого делать, если только мы не хотим вызывать проблемы, обозначенные в комментариях. Если мы отредактируем декремент в функции const, произойдет следующее:
NonConst: A
Const: B
Ясно, что, хотя A - это «Data [1]», он обрабатывается как «Data [0]», потому что указатель NonConst разрешил операцию декремента. Когда const реализован, как пишет другой человек, мы обнаруживаем потенциальную ошибку до ее появления.
Еще одно основное соображение заключается в том, что указатель const может использоваться в качестве псевдо-ссылки, поскольку вещь, на которую указывает ссылка, не может быть изменена (интересно, возможно, именно так и было реализовано). Рассматривать:
int main()
{
int A = 10;
int * const B = &A;
*B = 20; //This is permitted
printf("%d\n",A);
B = NULL; //This produces an error
}
При попытке компиляции выдает следующую ошибку:
ошибка: присвоение переменной только для чтения 'B'
Что, вероятно, плохо, если была нужна постоянная ссылка на А. Если B = NULL
это закомментировано, компилятор с радостью разрешит нам изменить *B
и, следовательно, A. Это может показаться бесполезным для int, но подумайте, если у вас была единственная позиция графического приложения, где вы хотели использовать неизменяемый указатель, ссылающийся на него, который вы могли бы передать вокруг.
Его использование является переменным (извините за непреднамеренное каламбур), но используется правильно, это еще один инструмент в коробке, чтобы помочь с программированием.