Пример того, где указатель 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
}
Получаем:
ошибка: в качестве левого операнда присваивания требуется lvalue // Снова произошла ошибка!
Очевидно, что мы можем изменять содержимое массива, но не указатель массива.Хорошо, если вы хотите убедиться, что указатель имеет согласованное состояние при передаче его обратно пользователю.Однако есть одна загвоздка:
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 никогда не будет изменен, подобно тому, как в настоящее время работает ссылка), тогда это очень применимо.Если вы хотите, чтобы пользователь имел полный доступ и изменил его, то для вас неконстантное.
Редактировать:
После того, как вы отметили комментарий 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 - это «Данные»[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, но подумайте, если у вас была единственная позиция графического приложения, где вы хотели использовать неизменяемый указатель, который ссылается нак нему, что вы могли бы обойти.
Его использование является переменным (извините за непреднамеренное каламбур), но используется правильно, это еще один инструмент в коробке, чтобы помочь с программированием.