Pregunta ¿Cuál es la diferencia entre const int *, const int * const e int const *?


Siempre estropeo la forma de usar const int*, const int * consty int const * correctamente. ¿Hay un conjunto de reglas que definen lo que puedes y no puedes hacer?

Quiero saber todo lo que se debe y lo que no se debe hacer en términos de asignaciones, pasar a las funciones, etc.


992
2017-07-17 13:28


origen


Respuestas:


Léelo al revés (según lo impulsado por Regla a la derecha / en espiral)

  • int* - puntero a int
  • int const * - puntero a const int
  • int * const - const puntero a int
  • int const * const - const puntero a const int

Ahora el primero const puede estar en cualquier lado del tipo así que:

  • const int * == int const *
  • const int * const == int const * const

Si quieres volverte loco, puedes hacer cosas como esta:

  • int ** - puntero a puntero a int
  • int ** const - un puntero const a un puntero a un int
  • int * const * - un puntero a un puntero const a un int
  • int const ** - un puntero a un puntero a un const int
  • int * const * const - un puntero const a un puntero const a un int
  • ...

Y para asegurarnos de que tenemos claro el significado de const

const int* foo;
int *const bar; //note, you actually need to set the pointer 
                //here because you can't change it later ;)

foo es un puntero variable a un entero constante. Esto le permite cambiar lo que señala pero no el valor que señala. La mayoría de las veces esto se ve con cadenas de estilo C donde tiene un puntero a const char. Puede cambiar a qué cadena apunta, pero no puede cambiar el contenido de estas cadenas. Esto es importante cuando la cadena en sí está en el segmento de datos de un programa y no debe modificarse.

bar es un puntero constante o fijo a un valor que se puede cambiar. Esto es como una referencia sin el azúcar sintáctico adicional. Debido a este hecho, generalmente usaría una referencia donde usaría un T* const puntero a menos que necesite permitir NULL punteros.


1740
2017-07-17 13:29



Para aquellos que no saben acerca de la Regla de Reloj / Espiral: Comience desde el nombre de la variable, muévase a la derecha (en este caso, retroceda) hasta el siguiente puntero o tipo. Repita hasta que termine la expresión.

aquí hay una demostración:

pointer to int

const pointer to int const

pointer to int const

pointer to const int

const pointer to int


232
2017-07-10 02:15



Creo que ya todo está respondido aquí, pero solo quiero agregar que debes tener cuidado con typedefs! NO son solo reemplazos de texto.

Por ejemplo:

typedef char *ASTRING;
const ASTRING astring;

El tipo de astring es char * constno const char *. Esta es una razón por la que siempre tiendo a const a la derecha del tipo, y nunca al comienzo.


123
2017-07-17 13:39



Como casi todos señalaron:

Cuál es la diferencia entre const X* p, X* const p y const X* const p?

Tienes que leer las declaraciones del puntero   De derecha a izquierda.

  • const X* p significa "p apunta a una X que es const": el objeto X no se puede cambiar a través de p.

  • X* const p significa "p es un puntero const a una X que no es const": no puede cambiar el puntero p en sí, pero puede cambiar el objeto X a través de p.

  • const X* const p significa que "p es un puntero const para una X que es const": no puede cambiar el puntero p en sí mismo, ni puede cambiar el objeto X a través de p.


44
2017-07-17 13:36



  1. Referencia constante:

    Una referencia a una variable (aquí int), que es constante. Pasamos la variable principalmente como referencia, porque las referencias son de menor tamaño que el valor real, pero hay un efecto secundario y es porque es como un alias de la variable real. Es posible que accidentalmente cambiemos la variable principal a través de nuestro acceso completo al alias, por lo que lo hacemos constante para evitar este efecto secundario.

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
    
  2. Punteros constantes

    Una vez que un puntero constante apunta a una variable, no puede apuntar a ninguna otra variable.

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
    
  3. Puntero a constante

    Un puntero a través del cual no se puede cambiar el valor de una variable a la que apunta se conoce como puntero a constante.

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
    
  4. Puntero constante a una constante

    Un puntero constante a una constante es un puntero que no puede cambiar la dirección a la que apunta y tampoco puede cambiar el valor guardado en esa dirección.

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error
    

39
2018-05-17 20:21



Esta pregunta muestra precisamente por qué me gusta hacer las cosas de la forma en que lo mencioné en mi pregunta ¿Es const el id de tipo aceptable?

En resumen, creo que la forma más fácil de recordar la regla es que el "const" se va después a lo que se aplica Entonces en su pregunta, "int const *" significa que int es constante, mientras que "int * const" significa que el puntero es constante.

Si alguien decide ponerlo en primer plano (por ejemplo: "const int *"), como excepción especial en ese caso se aplica a la cosa que está detrás de él.

A muchas personas les gusta usar esa excepción especial porque creen que se ve mejor. No me gusta porque es una excepción y confunde las cosas.


15
2017-07-17 13:52



La regla general es que el const la palabra clave se aplica a lo que le precede de inmediato. Excepción, un comienzo const se aplica a lo que sigue.

  • const int* es lo mismo que int const* y significa "puntero a constante int".
  • const int* const es lo mismo que int const* const y significa "puntero constante a int constante".

Editar: Para lo que se debe y lo que no se debe hacer, si esta respuesta no es suficiente, ¿podría ser más preciso sobre lo que quiere?


14
2017-07-17 13:30



Uso simple de 'const'

El uso más simple es declarar una constante nombrada. Para hacer esto, uno declara una constante como si fuera una variable pero agrega 'const' antes de ella. Uno debe inicializarlo inmediatamente en el constructor porque, por supuesto, uno no puede establecer el valor más tarde ya que eso lo estaría alterando. Por ejemplo,

const int Constant1=96; 

creará una constante entera, sin imaginación llamada 'Constant1', con el valor 96.

Dichas constantes son útiles para los parámetros que se utilizan en el programa, pero no es necesario cambiarlos una vez que se haya compilado el programa. Tiene una ventaja para los programadores sobre el preprocesador C '#define' en el sentido de que el compilador lo entiende y lo usa, no solo es sustituido en el texto del programa por el preprocesador antes de llegar al compilador principal, entonces los mensajes de error son mucho más útiles. .

También funciona con punteros, pero hay que tener cuidado donde 'const' determinar si el puntero o lo que apunta es constante o ambos. Por ejemplo,

const int * Constant2 

declara que Constant2 es un puntero variable a un entero constante y

int const * Constant2

es una sintaxis alternativa que hace lo mismo, mientras que

int * const Constant3

declara que Constant3 es un puntero constante a un entero variable y

int const * const Constant4

declara que Constant4 es un puntero constante a un entero constante. Básicamente, 'const' se aplica a lo que está a su izquierda inmediata (excepto si no hay nada allí, en cuyo caso se aplica a lo que sea su derecho inmediato).

árbitro: http://duramecho.com/ComputerInformation/WhyHowCppConst.html


12
2017-07-17 13:31



Tenía la misma duda que tú hasta que me encontré con esto libro por el C ++ Guru Scott Meyers. Consulte el tercer elemento de este libro donde habla en detalle sobre el uso const.

Solo sigue este consejo

  1. Si la palabra const aparece a la izquierda del asterisco, lo que se señala es constante
  2. Si la palabra const aparece a la derecha del asterisco, el puntero en sí mismo es constante
  3. Si const aparece en ambos lados, ambos son constantes

7
2018-03-21 13:56



Hay muchos otros puntos sutiles que rodean la corrección const en C ++. Supongo que la pregunta aquí simplemente ha sido sobre C, pero daré algunos ejemplos relacionados ya que la etiqueta es C ++:

  • A menudo pasa argumentos grandes como cadenas como TYPE const & que evita que el objeto sea modificado o copiado. Ejemplo:

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    Pero TYPE & const no tiene sentido porque las referencias siempre son const.

  • Siempre debe etiquetar los métodos de clase que no modifican la clase como const, de lo contrario no puede llamar al método desde TYPE const & referencia. Ejemplo:

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • Hay situaciones comunes en las que tanto el valor de retorno como el método deberían ser const. Ejemplo:

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

    De hecho, los métodos const no deben devolver los datos internos de la clase como referencia-a-no-const.

  • Como resultado, a menudo se debe crear tanto un método const como uno sin const utilizando la sobrecarga const. Por ejemplo, si defines T const& operator[] (unsigned i) const;, entonces probablemente también querrás la versión no const dada por:

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

Afaik, no hay funciones const en C, las funciones no miembro no pueden ser const en C ++, los métodos const pueden tener efectos secundarios, y el compilador no puede usar las funciones const para evitar llamadas a funciones duplicadas. De hecho, incluso un simple int const & la referencia puede ser testigo de que el valor al que se refiere se modifique en otro lugar.


5
2017-09-13 10:50