Um exemplo de onde um ponteiro const é altamente aplicável pode ser demonstrado assim. Considere que você tem uma classe com uma matriz dinâmica dentro dela e deseja passar o acesso do usuário à matriz, mas sem conceder a eles os direitos de alterar o ponteiro. Considerar:
#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());
}
Qual produz:
Os dados de entrada
colocar dados
Mas se tentarmos isso:
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
}
Nós temos:
error: lvalue necessário como operando esquerdo da atribuição // Drat frustrado novamente!
Tão claramente que podemos modificar o conteúdo da matriz, mas não o ponteiro da matriz. Bom se você quiser garantir que o ponteiro tenha um estado consistente ao transmiti-lo ao usuário. Há uma captura, no entanto:
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!
}
Ainda podemos excluir a referência de memória do ponteiro, mesmo que não possamos modificar o ponteiro em si.
Portanto, se você deseja que a referência de memória sempre aponte para algo (o IE nunca é modificado, semelhante ao modo como uma referência atualmente funciona), é altamente aplicável. Se você deseja que o usuário tenha acesso total e o modifique, o non-const é para você.
Editar:
Depois de observar o comentário okorz001 de não poder atribuir devido ao fato de GetArray () ser um operando de valor certo, o comentário dele está totalmente correto, mas o acima descrito ainda se aplica se você retornar uma referência ao ponteiro (suponho que assumi que GetArray era referente a uma referência), por exemplo:
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
}
Retornará no primeiro, resultando em um erro:
erro: atribuição do local somente leitura 'Temp.TestA :: GetArray ()'
Mas o segundo ocorrerá alegremente, apesar das possíveis conseqüências subjacentes.
Obviamente, a questão será levantada 'por que você gostaria de retornar uma referência a um ponteiro'? Existem casos raros em que você precisa atribuir memória (ou dados) diretamente ao ponteiro original em questão (por exemplo, criar seu próprio front-end malloc / free ou novo / free), mas nesses casos é uma referência não constante . Como referência a um ponteiro const, não encontrei uma situação que o justificasse (a menos que talvez como variáveis declaradas de referência const em vez de tipos de retorno?).
Considere se temos uma função que aceita um ponteiro const (versus um que não possui):
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");
}
O erro na const produz a seguinte mensagem:
erro: decremento do parâmetro somente leitura 'Dados'
O que é bom, pois provavelmente não queremos fazer isso, a menos que desejemos causar os problemas indicados nos comentários. Se editarmos o decremento na função const, ocorrerá o seguinte:
NãoConst: A
Const: B
Claramente, embora A seja 'Dados [1]', ele está sendo tratado como 'Dados [0]' porque o ponteiro NonConst permitiu a operação de decremento. Com o const implementado, como outra pessoa escreve, detectamos o bug em potencial antes que ele ocorra.
Uma outra consideração principal é que um ponteiro const pode ser usado como uma pseudo referência, pois a coisa para a qual os pontos de referência não podem ser alterados (é de se perguntar, se talvez fosse assim que foi implementado). Considerar:
int main()
{
int A = 10;
int * const B = &A;
*B = 20; //This is permitted
printf("%d\n",A);
B = NULL; //This produces an error
}
Ao tentar compilar, produz o seguinte erro:
erro: atribuição da variável somente leitura 'B'
O que provavelmente é uma coisa ruim se uma referência constante a A for desejada. Se B = NULL
for comentado, o compilador nos permitirá modificar *B
e, portanto, A. Isso pode não parecer útil com ints, mas considere se você tinha uma única postura de um aplicativo gráfico em que desejava um ponteiro não modificável que se referisse a ele que você poderia passar por aí.
Seu uso é variável (desculpe o trocadilho não intencional), mas usado corretamente, é outra ferramenta na caixa para ajudar na programação.