Para começar, você provavelmente sabe que const
pode ser usado para tornar os dados de um objeto ou um ponteiro não modificáveis ou ambos.
const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer
No entanto, você também pode usar a sintaxe:
Object const *obj; // same as const Object* obj;
A única coisa que parece importar é de que lado do asterisco você colocou a const
palavra - chave. Pessoalmente, prefiro colocar const
à esquerda do tipo para especificar que os dados não são modificáveis, pois acho que eles são melhores na minha mentalidade da esquerda para a direita, mas qual sintaxe veio primeiro?
Mais importante ainda, por que existem duas maneiras corretas de especificar const
dados e em que situação você preferiria ou precisaria uma sobre a outra, se houver?
Editar:
Parece que essa foi uma decisão arbitrária quando o padrão de como os compiladores deveriam interpretar as coisas foi elaborado muito antes de eu nascer. Como const
é aplicado ao que fica à esquerda da palavra-chave (por padrão?), Acho que eles descobriram que não havia mal em adicionar "atalhos" para aplicar palavras-chave e digitar qualificadores de outras maneiras pelo menos até que a declaração seja alterada por analisando um * ou & ...
Este foi o caso em C também, então eu estou assumindo?
const
após o tipo, por exemplo, em#define MAKE_CONST(T) T const
vez de,#define MAKE_CONST(T) const T
paraMAKE_CONST(int *)
expandir corretamente para emint * const
vez deconst int *
.Respostas:
Essencialmente, a razão pela qual a posição dos
const
especificadores anteriores a um asterisco não importa é que a gramática C foi definida dessa maneira por Kernighan e Ritchie.A razão pela qual eles definiram a gramática dessa maneira era provável que seu compilador C analisasse a entrada da esquerda para a direita e terminasse de processar cada token à medida que o consumia. Consumir o
*
token altera o estado da declaração atual para um tipo de ponteiro. Encontrarconst
depois*
significa que oconst
qualificador é aplicado a uma declaração de ponteiro; encontrá-lo antes dos*
meios em que o qualificador é aplicado aos dados apontados.Como o significado semântico não muda se o
const
qualificador aparecer antes ou depois dos especificadores de tipo, ele é aceito de qualquer maneira.Um tipo semelhante de caso surge ao declarar ponteiros de função, em que:
void * function1(void)
declara uma função que retornavoid *
,void (* function2)(void)
declara um ponteiro de função para uma função que retornavoid
.Novamente, o que se deve notar é que a sintaxe do idioma suporta um analisador da esquerda para a direita.
fonte
*
analisador do compilador não saiba que é um ponteiro, é uma constante para o valor dos dados. Depois de *, ele está relacionado ao ponteiro constante. Brilhante. E, finalmente, explica por que posso fazerconst char
tão bem quantochar const
.const
que sempre viesse depois da coisa qualificada ... exatamente para que eu pudesse sempre terminar o processamento da const imediatamente após consumi-la. Portanto, este parece ser um argumento para proibir a const-oeste, em vez de permitir.++
operador? "A frase", imho, me ajudou a perceber que não havia outra razão em particular senão porque eles podiam. Talvez eles fizessem uma escolha diferente hoje / talvez não.A regra é:
Eu prefiro usar const à direita da coisa para ser const apenas porque é a maneira "original" de const ser definida.
Mas acho que esse é um ponto de vista muito subjetivo.
fonte
Object const *
é um ponteiro para um objeto const. Se você colocar oconst
lado esquerdo, ele seria lido como um ponteiro para um Objeto que é const, que realmente não flui muito bem.const
não é uma classe de armazenamento, mas as pessoas não são analisadoras).Eu prefiro a segunda sintaxe. Isso me ajuda a acompanhar o que é constante lendo a declaração de tipo da direita para a esquerda:
fonte
Object const* const
não éconst const Object*
. "const" não pode estar à esquerda, exceto no caso especial em que tantas pessoas o adoram. (Veja Heath acima.)A ordem das palavras-chave em uma declaração não é tão fixa assim. Existem muitas alternativas para "a única ordem verdadeira". Como isso
ou deveria ser
??
fonte
decl-specifier-seq
é uma sequência dedecl-specifier
s. Não há uma ordem dada pela gramática, e o número de ocorrências de cada palavra-chave é limitada apenas por algumas regras semânticas (você pode ter umconst
, mas doislong
:-)unsigned
é um tipo, o mesmo queunsigned int
eint unsigned
.unsigned long
é um outro tipo, a mesma comounsigned long int
eint long unsigned
. Veja o padrão?;)
. OK, obrigadostatic
à confusão de palavras, mas apenas recentemente os compiladores reclamaram questatic
precisava vir em primeiro lugar.A primeira regra é usar o formato que seus padrões de codificação local exigirem. Depois disso: colocar a
const
frente não gera confusão quando os typedefs estão envolvidos, por exemplo:Se o seu padrão de codificação permitir typedef de ponteiros, ele realmente deve insistir em colocar a const após o tipo. Em todos os casos, exceto quando aplicado ao tipo, const deve seguir o que se aplica; portanto, a coerência também argumenta a favor do const depois. Mas as diretrizes locais de codificação superam tudo isso; a diferença normalmente não é importante o suficiente para voltar e alterar todo o código existente.
fonte
const std::string::const_iterator
bem para uma boa medida;)const IntPtr p1
significar além de "ponteiro inteiro constante" (ou seja, "ponteiro constante para inteiro")? Ninguém em sã consciência, mesmo sem saber comoIntPtr
é definido, pensaria que issop1
é mutável. E, por falar nisso, por que alguém assumiria incorretamente que isso*p1
é imutável? Além do mais, colocar o const em qualquer outro lugar (por exemploIntPtr const p1
) não altera a semântica.std::vector<T>::const_iterator
, onde não é o iterador que é const, mas o que ele está apontando).Existem razões históricas para a esquerda ou direita serem aceitáveis. Stroustrup adicionou const ao C ++ em 1983 , mas não chegou ao C até C89 / C90.
Em C ++, há um bom motivo para sempre usar const à direita. Você será consistente em todos os lugares porque as funções de membro const devem ser declaradas desta maneira:
fonte
const int& getInt();
int& const getInt();
int const& getInt();
é melhor do que o equivalente,const int& getInt();
considerandoint& const getInt();
que você o compara com é redundante (as referências já são constantes), embora legais e geralmente dará um aviso. De qualquer forma, const em uma função de membro altera othis
ponteiro na função deFoo* const
paraFoo const* const
.const
em uma função membro não significa a mesma coisa - ou évoid set(int)&;
algum tipo de referência a uma função?