const char c++
¿Significa "const" solo lectura o algo más? (7)
Al declarar una variable como const
compilador que no tienes intenciones de modificar esa variable. ¡Pero no significa que otros no tienen! Es solo para permitir cierta optimización y recibir una notificación mediante un error de compilación (nota, que es principalmente un error de compilación, mientras que const == ReadOnly
significaría errores de tiempo de ejecución).
const
no significa solo lectura , porque puedes escribir const volatile
, eso significaría que podría cambiar por sí mismo en cualquier momento, pero no tengo intenciones de modificarlo.
EDITAR: aquí hay un ejemplo clásico: considere que estoy escribiendo el código que lee la hora actual desde un puerto mapeado en memoria. Tenga en cuenta que RTC se asigna a la memoria DWORD 0x1234.
const volatile DWORD* now = (DWORD*)0x1234;
Es const
porque es un puerto de solo lectura, y es volatile
porque cada vez que lo leo cambiará.
También tenga en cuenta que muchas arquitecturas hacen que las variables globales se declaren como const
de solo lectura porque es UB para modificarlas. En estos casos, UB se manifestará como un error de tiempo de ejecución. En otros casos, sería un UB real :)
Aquí hay una buena lectura: http://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html
¿Qué significa realmente const
? La opción de solo lectura parece encapsular su significado para mí, pero no estoy seguro de tener razón.
Si solo lectura y const
son diferentes, ¿podría alguien decirme por qué?
Lo que provocó esta pregunta fue esta respuesta en la que afirma que const
"solo" significa solo lectura en C. Pensé que eso era todo lo que quería decir, independientemente de si era C o C ++. ¿Qué quiere decir?
Para una respuesta a las diferencias específicas en const
en C vs C ++, he creado una nueva pregunta: ¿En qué se diferencia "const" en C y C ++? según la sugerencia de R ..
C ++ permite la definición de las funciones miembro de const. Las funciones miembro de const son las únicas funciones que se invocan en los objetos const. Además, las funciones miembro de const no pueden modificar ningún miembro de datos de una clase (a menos que el miembro de datos marque mutable).
class Foo
{
int data;
void Bar();
void ConstBar() const;
};
void Foo::ConstBar() const
{
// Error! cannot modify i as ConstBar is a const member function.
// i = 0;
}
// Usage:
const Foo foo_instance;
// Error! cannot call non-const member on a const object.
// foo_instance.Bar();
// OK
foo_instance.ConstBar();
Const significa que un puntero o referencia no se puede usar para una operación de escritura o lectura-modificación-escritura sin descartar const. NO significa lo que el estándar C ++ intenta afirmar que significa (el estándar C ++ es simplemente incorrecto en esto).
Una variable definida así:
/* auto */ int const x = 1;
evidentemente NO es de solo lectura ya que de lo contrario no podría inicializarse. Más bien, el tipo de variable x es "referencia const a int" (y NO referencia a const int) o alternativamente lvalue const de int. Tenga en cuenta que el "const" está asociado con un puntero o referencia que no tiene nada que ver con el almacenamiento, ni con el tipo del valor que reside en ese almacenamiento.
Esto es bastante desafortunado porque el contrato proporcionado por const es extremadamente débil y, en particular, no permite el almacenamiento en memoria caché de una ubicación de memoria apuntada o referida, precisamente porque NO significa un almacenamiento inmutable.
El resultado final es: const es un modificador de acceso asociado con una referencia simbólica o un puntero que es usado por el programador para permitir que el proveedor de símbolos establezca una obligación en el cliente de símbolo, o para el cliente de símbolo para prometerle al proveedor de símbolo que no lo hace modificar el almacenamiento a través de este símbolo (por ejemplo, una función que acepta un puntero const a int promete no modificar el apuntado en int).
Esto no tiene nada que ver con las variables:
int const *p = (int*)malloc(sizeof(int));
y claramente poco que ver con el almacenamiento (la tienda malloc''ed siempre puede escribirse).
En su lugar, debe pensar en const como una forma de comunicar invariantes, obligaciones o requisitos entre partes del programa, establecidos por el programador para los propósitos de los programadores, y propagados por el sistema de tipos. Lamentablemente, el sistema de tipos no es sólido y no puede propagar correctamente la constness correctamente:
X *last;
struct X { int a; X() : a(0) { last=this; } };
X const x; // x is const?
last->a = 1; //really ??
En mi humilde opinión, la única oportunidad que tiene un compilador para hacer que la tienda sea inmutable es para las constantes reales, como los literales de cadena (tal vez) o el almacenamiento estático (global). El almacenamiento automático, dinámico y temporal no se puede hacer de solo lectura en la práctica.
Dos bytes para bytes idénticos (excepto para los comentarios) ejemplos mínimos de casos ...
Primero en C, gcc emitirá una advertencia ...
/* Function taking a pointer to an array of two read only integers.*/ void a( const int (* parray)[2]); void b(void) { int array[2] = {1,2}; const int crray[2] = {1,2}; /* C reserves the right to stash this in a read-only location.*/ a( &array); /* warning: passing argument 1 of ‘a’ from incompatible pointer type*/ a( &crray); /* OK!*/ }
Ahora lo mismo en C ++ ... g ++ es bastante feliz con eso.
// Function taking a pointer to an array // of two integers which it promises not to modify. // (Unless we cast away it''s constness ;-P) void a( const int (* parray)[2]); void b(void) { int array[2] = {1,2}; const int crray[2] = {1,2}; a( &array); // C++ has no problem with this. a( &crray); // OK! }
El compilador no permitirá que se modifique algo declarado como const
. Es como dices.
Se usa principalmente en prototipos de funciones para informar al usuario que una función no tocará esto o aquello cuando se pasen los punteros. También funciona como una especie de seguridad para usted.
Mucha gente te dice que const
significa que no puedes modificarlo. Eso es patentemente falso . const
puede ser arrojado trivialmente. Tenga en cuenta este fragmento:
void foo(const int *somevalue)
{
int *p = (int*) somevalue;
*p = 256; // OMG I AM EVIL!!!!11
}
Tu compilador no te impedirá hacer esto. Entonces, ¿cuál es el propósito de const
? Lo llamaría más una sugerencia. Te recuerda cuando miras los prototipos de función del contrato que esperan tus funciones. Tu compilador te gritará si lo rompes sin cuidado. (Pero no si lo rompes intencionalmente, como en el modelo anterior).
En algunos casos, el estándar rompe intencionalmente const
. Tenga en cuenta los valores de retorno de strstr
por ejemplo: por definición, devolverá una compensación en el búfer de const
que le proporcione ... Pero el valor devuelto no es const
. ¿Por qué? Bueno, esto se rompería de manera significativa utilizando el valor de retorno de strstr
en un buffer no const
.
const char * hello_1{ "Hello!" };
const char hello_2[]{ "Hello!" };
char * ptr{};
// take away the const-nes
// ptr = (char *)hello_1;
// *ptr = ''*''; <-- write access violation
// hello_1 is in a read only memory
// take away the const-nes
ptr = (char *)hello_2;
*ptr = ''*''; // <-- OK
// hello_2 is modifiable
Los punteros apuntan a la memoria, y los puntos char *
a la memoria en el segmento de datos que es de solo lectura. La diferencia entre char *
y char []
es que si bien ambos se declaran de la misma manera en el segmento de datos, char []
se trata como legible porque se inserta en la pila si se usa.