2008-10-20 18 views
26

que he usado a menudo punteros a const objetos, al igual que ...¿Para qué sirven los punteros const (a diferencia de los punteros para crear objetos)?

const int *p; 

Eso significa simplemente que no se puede cambiar el entero que p está señalando a través de p. Pero también he visto referencia a punteros const, declarada como esto ...

int* const p; 

Como yo lo entiendo, que significa que la variable puntero sí es constante - se puede cambiar el número entero que apunta a todo el día, pero no puedes hacer que apunte a otra cosa.

¿Qué uso posible podría tener?

Respuesta

25

Cuando diseña programas C para sistemas integrados o programas de propósito especial que necesitan referirse a la misma memoria (aplicaciones multiprocesador que comparten memoria), entonces necesita punteros constantes.

Por ejemplo, tengo un 32 bit MIPs processor que tiene un little LCD anexado. Tengo que escribir los datos de mi LCD en un puerto específico en la memoria, que luego se envía al controlador LCD.

Podría #definir ese número, pero luego también tengo que convertirlo en un puntero, y el compilador de C no tiene tantas opciones cuando lo hago.

Además, podría necesitar que sea volátil, lo que también se puede convertir, pero es más fácil y más claro utilizar la sintaxis proporcionada: un indicador de contacto para una ubicación de memoria volátil.

Para programas de PC, un ejemplo sería: Si diseña juegos VGA DOS (hay tutoriales en línea que son divertidos de aprender para aprender gráficos básicos de bajo nivel), entonces necesita escribir en la memoria VGA, que podría ser referenciado como un desplazamiento desde un puntero const.

-Adam

+3

Minit nitpick: para dispositivos mapeados en memoria, ciertamente (no "podría") necesitar que el elemento se marque como volátil; de lo contrario, no podría estar seguro de si el compilador realmente emitiría la operación de lectura o escritura o cuándo. –

+0

Usted podría necesitar volátil es correcto. Puede usar 'barrier()' y otra semántica dependiendo del dispositivo. Es cierto que necesita manejar los valores cuidadosamente. Es decir, caché/no-caché, barrera, etc. Depende del tipo de dispositivo y ** volátil ** no siempre es la mejor opción. –

+0

@MichaelBurr: estoy de acuerdo con usted en que el 'volátil' ciertamente debe estar ahí; por otro lado, muchos encabezados de proveedores de compiladores no parecen molestarse, un hecho que puede ser algo molesto (ya que incluso si los compiladores generalmente hacen lo correcto, pueden ignorar los intentos de leer un registro pero no hacer nada con el resultado). – supercat

3

Igual que "const int" ... si el compilador sabe que no va a cambiar, puede haber suposiciones de optimización basadas en eso.

struct MyClass 
{ 
    char* const ptr; 
    MyClass(char* str) :ptr(str) {} 

    void SomeFunc(MyOtherClass moc) 
    { 
     for(int i=0; i < 100; ++i) 
     { 
       printf("%c", ptr[i]); 
       moc.SomeOtherFunc(this); 
     } 
    } 
} 

Ahora, el compilador podría hacer un poco de optimizar ese bucle --- siempre y cuando sabe que SomeOtherFunc() no cambia el valor de la PTR. Con la const, el compilador lo sabe y puede hacer suposiciones. Sin él, el compilador tiene que suponer que SomeOtherFunc cambiará ptr.

+0

¿No será necesario declarar SomeOtherFunc con un argumento const pointer para que esto se compile? ¿Y no será eso también cómo el compilador sabría que SomeOtherFunc no cambiará el puntero? Entonces, declarar el puntero local como const no parece ayudar. –

+0

Andrew: Creo que estás confundiendo ptr con este –

+0

@Andrew: No.SomeOtherFunc está completamente permitido para cambiar cualquier otra parte del objeto MyClass. –

7

otro ejemplo: si sabe dónde se ha inicializado, puede evitar futuras comprobaciones NULL. El compilador le garantiza que el puntero nunca ha cambiado (a NULO) ...

+1

En C. En C++, en su caso particular (es decir, punteros no NULL), utiliza referencias en su lugar. – paercebal

2

He visto un código OLE donde había un objeto pasado desde fuera del código y para trabajar con él, tenía que acceder a la memoria específica que pasó. Así que usamos punteros const para asegurarnos de que las funciones siempre manipulaban los valores que ingresaban a través de la interfaz OLE.

5

En cualquier no-const C++ función miembro, el puntero this es de tipo C * const, donde C es el tipo de clase - se puede cambiar a lo que apunta (es decir, sus miembros), pero no se puede cambiar a apunte a una instancia diferente de C.Para las funciones de miembro const, this es del tipo const C * const. También existen (raramente se encuentran) volatile y const volatile funciones de miembro, para las cuales this también tiene el calificador volatile.

3

Siempre los he usado cuando quería evitar modificaciones involuntarias en el puntero (como la aritmética del puntero o dentro de una función). También puede usarlos para patrones de Singleton.

'this' es un puntero constante codificado.

26

Le permite proteger el puntero de ser cambiado. Esto significa que puede proteger a los supuestos que tome basadas en el puntero que nunca cambia o no intencional de la modificación, por ejemplo:

int* const p = &i; 

... 

p++;  /* Compiler error, oops you meant */ 
(*p)++; /* Increment the number */ 
+1

Nunca había visto eso antes y acepto que es un truco muy útil. – Rob

+1

No es un truco :). Intento usar const cuando sea posible con argumentos de funciones para que quede claro que la función no modificará la cadena o la estructura que se pasa. –

+0

Lo confuso es que const a menudo aparece dos veces en una declaración, y en realidad puede estar en algunas posiciones diferentes Comúnmente, podría aparecer como algo como 'const uint8 * const value'. Esto declara que el puntero y el valor al que apunta no son modificables (pero pueden ser cascados). –

-2

siempre pienso en un puntero como un int. esto significa que

object* var; 

en realidad puede ser pensado como

int var; 

así, un puntero constante significa simplemente que:

const object* var; 

convierte

const int var; 

y por lo tanto U no puede cambiar la dirección que th El puntero también apunta, y eso es todo. Para evitar el cambio de datos, debe convertirlo en un puntero a un objeto const.

+0

Los punteros son ** no ** 'int's, de varias formas. Además, la pregunta se expresa muy claramente como acerca de _'const' pointers_, no _pointers to 'const' objects_. Pero los has equivocado de todos modos. –

1

Se han dado varias buenas razones para responder a estas preguntas (dispositivos con memoria asignada y codificación defensiva simple), pero estaría dispuesto a apostar que la mayoría de los casos en que ve esto es un error y que el La intención era tener que el elemento ser un puntero-a-const.

Ciertamente no tengo datos para respaldar esta corazonada, pero aún así haré la apuesta.

+0

lo uso mucho para la optimización. – DavidG

+0

@DavidG ¿Cómo importa exactamente 'const' para la optimización? Cualquier compilador inteligente puede determinar si se modifica una variable y se optimiza si puede basarse en eso, ya sea que usted lo haya dicho o no. –

+0

lo hice en 2008 en algunos dispositivos cuando escribí este comentario ... pero el mundo ha cambiado mucho desde entonces, y ahora los compiladores han mejorado mucho. – DavidG

5

Un uso es en código de bajo nivel (controlador de dispositivo o incrustado) donde debe hacer referencia a una dirección específica asignada a un dispositivo de entrada/salida como un pin de hardware. Algunos idiomas le permiten vincular variables en direcciones específicas (por ejemplo, Ada tiene use at). En C, la forma más idiomática de hacer esto es declarar un puntero constante. Tenga en cuenta que dichos usos también deben tener el calificador volatile.

Otras veces es solo codificación defensiva. Si tiene un puntero que no debe cambiar, es prudente declararlo de manera que no puede cambiar. Esto permitirá que el compilador (y las herramientas de pelusa) detecten intentos erróneos de modificarlo.

0

Piense en tipo * y const tipo * como los tipos de sí mismos. Entonces, puedes ver por qué querrías tener un const de esos tipos.

+0

sí, y ese tipo es básicamente un int. – DavidG

Cuestiones relacionadas