constint c++ c const declaration

c++ - constint



¿Regla fácil de leer declaraciones complicadas de const? (2)

Para leer declaraciones de punteros complejos, existe la regla de derecha a izquierda .

Pero esta regla no menciona cómo leer los modificadores de const .

Por ejemplo, en una declaración de puntero simple, const se puede aplicar de varias maneras:

char *buffer; // non-const pointer to non-const memory const char *buffer; // non-const pointer to const memory char const *buffer; // equivalent to previous declartion char * const buffer = {0}; // const pointer to non-const memory char * buffer const = {0}; // error const char * const buffer = {0}; // const pointer to const memory

Ahora, ¿qué pasa con el uso de const con un puntero de declaración de puntero?

char **x; // no const; const char **x; char * const *x; char * * const x; const char * const * x; const char * * const x; const char * const * const x;

¿Y cuál es una regla fácil de leer esas declaraciones? ¿Qué declaraciones tienen sentido?

¿Es aplicable la regla de las agujas del reloj / espiral ?

Dos ejemplos del mundo real

El método ASTUnit::LoadFromCommandLine usa const char ** para suministrar argumentos de línea de comando (en la fuente de clanv llvm).

El parámetro de vector argumento de getopt() se declara así:

int getopt(int argc, char * const argv[], const char *optstring);

Donde char * const argv[] es equivalente a char * const * argv en ese contexto.

Dado que ambas funciones usan el mismo concepto (un vector de punteros a cadenas para suministrar los argumentos) y las declaraciones difieren, las preguntas obvias son: ¿por qué difieren? Tiene un sentido más que el otro?

La intención debería ser: El modificador const debe especificar que la función no manipula las cadenas de este vector y no cambia la estructura del vector.


(Tratando de enfocarse en otros aspectos de la pregunta)

La regla de oro para las declaraciones de const es leerlas de derecha a izquierda y const modifica el próximo token. Excepción: al comienzo de una declaración, const modifica el token anterior.

Hay una razón de ser detrás de esta excepción : para las declaraciones elementales, const char c busca a algunas personas más naturales que char const c , y se informa que una forma precursora de const char c es anterior a la regla const final.

getopt

int getopt(int argc, char * const argv[], const char *optstring);

o

int getopt(int argc, char * const * argv, const char *optstring);

Lo que significa que argv es un puntero al vector const de punteros a cadenas no const.

Pero uno esperaría seguir la declaración:

int getopt(int argc, char const * const * argv, const char *optstring);

(puntero al vector const para const cadenas)

Debido a que getopt() no se supone que cambie las cadenas a las que se hace referencia mediante argv.

Al menos char ** (como se usa en main() ) se convierte automáticamente en char * const * argv .

Sonido metálico

ASTUnit::LoadFromCommandLine(..., const char **argv, ...);

Lo que significa que argv es un puntero a un conjunto de punteros no const para const cadenas.

Nuevamente uno esperaría const char * const *argv por la misma razón que arriba.

Pero esto es más notable porque char ** no se convierte en const char ** , por ejemplo

int main(int argc, char **argv) { const char **x = argv; // Compile error! return 0; }

produce un error de compilación, donde

int main(int argc, char **argv) { char * const *x = argv; return 0; }

y

int main(int argc, char **argv) { const char * const *x = argv; return 0; }

no haga.


El modificador const es trivial: modifica lo que le precede, a menos que nada lo preceda. Asi que:

char const* buffer; // const modifies char char* const buffer; // const modifies *

, etc. En general, es mejor evitar las formas en las que nada precede a la const , pero en la práctica, las vas a ver, así que debes recordar que cuando ningún tipo precede a la const , tienes que moverla lógicamente detrás del primer tipo. Asi que:

const char** buffer;

es de hecho:

char const** buffer;

, es decir, puntero a puntero para const char.

Finalmente, en una declaración de función, a [] after lee como a * before. (De nuevo, es probable que sea mejor evitar esta notación engañosa, pero la verás, así que debes lidiar con ella). Entonces:

char * const argv[], // As function argument

es:

char *const * argv,

un puntero a un puntero const a un char.