2012-01-10 19 views
14

entiendo que un puntero constante se puede declarar un par de maneras:C++: Const corrección y puntero argumentos

const int * intPtr1; // Declares a pointer that cannot be changed. 
int * const intPtr2; // Declares a pointer whose contents cannot be changed. 

// EDIT: THE ABOVE CLAIMS ARE INCORRECT, PLEASE READ THE ANSWERS. 

Pero ¿qué pasa con los mismos principios dentro del contexto de argumentos de la función?

quiero suponer que la siguiente es redundante:

void someFunc1(const int * arg); 
void someFunc2(int * arg); 

Desde someFunc 1 y 2 hacen un pase-por-valor para el indicador sí mismo, es imposible para someFunc1 para cambiar el valor del puntero original, en una llamada dada a la función. Para ilustrar:

int i = 5; 
int * iPtr = &i; 

someFunc1(iPtr); // The value of iPtr is copied in and thus cannot be changed by someFunc1. 

Si esto es verdad, entonces no hay punto en vez de declarar una función con un '* ptr const int' arg tipo, ¿verdad?

+13

Usted tiene sus declaraciones al revés. "const int *" es un puntero modificable a una int inmutable. "int * const" es un puntero inmutable a un int. modificable. –

+3

No, lo tienes al revés. –

+4

Se editó la pregunta para que los gatillos felices gatillo no se salgan mal informados. Dejé el error para que las respuestas aún tengan ese contexto. – Ben

Respuesta

25

lo tienes al revés:

const int * intPtr1; // Declares a pointer whose contents cannot be changed. 
int * const intPtr2; // Declares a pointer that cannot be changed. 

La siguiente const es de hecho innecesaria, y no hay razón para ponerlo en una función declaración:

void someFunc1(int * const arg); 

Sin embargo, es posible que desee ponerlo en la función implementación, por la misma razón que puede querer declarar una variable local (o cualquier otra cosa) const - la implementación puede ser más fácil de seguir cuando sabe que ciertas cosas no cambiarán. Puede hacerlo independientemente de si está o no declarado const en cualquier otra declaración de la función.

+0

Ahora me veo como un tonto ... ¡Gracias por la explicación concisa y afirmando que de hecho hay una const innecesaria en una de esas definiciones! – Ben

+0

¿hay alguna diferencia entre 'const int * intPtr1' y' int const * intPtr1; '? – dynamic

+5

@ yes123: No hay diferencia en absoluto. 'const' califica lo que tiene delante, a menos que sea al principio, en cuyo caso califica lo primero. Entonces, en ambos casos, califica el 'int', no el puntero. 'int * const' calificaría el puntero. –

2

Sí, está en lo cierto (ignorando el hecho de que los recibió de manera incorrecta) - no tiene sentido tomar los parámetros de referencia const. Además, no tiene sentido devolver valores que no sean de referencia const.

+0

Los valores de retorno 'const' sin referencia son incluso perjudiciales. – Xeo

+0

@Xeo: ¿Podrías profundizar en eso, por favor? ¡No sabía que tuvieran ningún efecto en absoluto! – ruakh

+0

@ruakh: Consulte [¿Cuándo un tipo de retorno const interfiere con la creación de instancias de plantilla?] (Http://stackoverflow.com/questions/2926319/when-does-a-const-return-type-interfere-with-template-instantiation) Es un problema bastante menor. –

22

Bueno, no es para la persona que llama, sino para el código dentro de someFunc1. De modo que cualquier código dentro de someFunc1 no lo cambiará accidentalmente. como

void someFunc1(int *arg) { 
    int i = 9; 
    arg = &i; // here is the issue 
    int j = *arg; 
} 

Vamos a hacer un poco de estudio de caso:

1) Sólo haciendo que el valor const puntas

void someFunc1(const int * arg) { 
int i = 9; 
*arg = i; // <- compiler error as pointed value is const 
} 

2) Sólo haciendo que el puntero constante

void someFunc1(int * const arg) { 
int i = 9; 
arg = &i; // <- compiler error as pointer is const 
} 

3) La forma correcta de usar const si las variables involucradas pueden ser const:

void someFunc1(const int * const arg) { 
    int i = 9; 
    *arg = i; // <- compiler error as pointed value is const 
    arg = &i; // <- compiler error as pointer is const 
} 

Esto debería despejar todas las dudas. Por lo tanto, ya mencioné que está destinado para el código de función y no para el que llama y debe usar el más restrictivo de los 3 casos que mencioné anteriormente.

EDIT:

  • Incluso en las declaraciones de funciones es una buena práctica para declarar const. Esto no solo aumentará la legibilidad, sino que la persona que llama conocerá el contrato y tendrá más confianza con respecto a la inmutabilidad de los argumentos. (Esto es necesario porque generalmente comparte los archivos de encabezado para que la persona que llama no tenga su archivo c/cpp de implementación)
  • Incluso el compilador puede señalar mejor si la declaración y las definiciones están sincronizadas.
+0

Pero eso no explica por qué escribirías 'void someFunc1 (const int * arg);'. Tenga en cuenta que predeclaring 'someFunc1' como' void someFunc1 (int * arg); 'todavía le permite definirlo como' void someFunc1 (int * const arg) {...} 'si lo desea; la 'const'-ness de la variable de parámetro en sí no afecta la firma de la función real. – ruakh

+0

@ruakh pls pasar por la ans actualizada. Eso debería ser tu preocupación. – havexz

+0

Lo sentimos, no, su respuesta actualizada aún no responde la pregunta. (Consulte la respuesta de Mike Seymour, arriba, para obtener la respuesta correcta). – ruakh

6

Tiene su lógica al revés. Debería leer el tipo al revés, por lo que const int * es un puntero a const int y int * const es un puntero const a un int.

Ejemplo:

void foo() { 
    int a = 0; 
    int b = 0; 

    int * const ptrA = &a; 
    *ptrA = 1; 
    ptrA = &b; ///< Error 

    const int * ptrB = &a; 
    *ptrB = 1; ///< Error 
    ptrB = &b; 

    const int * const ptrC = &a; 
    *ptrC = 1; ///< Error 
    ptrC = &a; ///< Error 
} 

para elaborar y mostrar por qué se desea que el parámetro de la función de ser un const int * es posible que desee para indicar a la persona que llama que deben pasar en un int porque en función quieren cambiar el valor Considere este código, por ejemplo:

void someFunc1(const int * arg) { 
    // Can't change *arg in here 
} 

void someFunc2(int * arg) { 
    *arg = 5; 
} 

void foo() { 
    int a = 0; 
    someFunc1(&a); 
    someFunc2(&a); 

    const int b = 0; 
    someFunc1(&b); 
    someFunc2(&b); ///< *** Error here. Must pass in an int not a const int. 
} 
2

lo tienes en la dirección equivocada:

const int * intPtr1; // Declares a pointer whose contents cannot be changed. 
int * const intPtr2; // Declares a pointer that cannot be changed. 

En términos generales es más fácil de razonar sobre constness cuando escribiendo esa expresión ligeramente diferente: const int* es del mismo tipo que int const *. En ese notación las reglas son mucho más clara, const siempre se aplica al tipo anterior que, por lo tanto:

int const * intPtr1; // Declares a pointer to const int. 
int * const intPtr2; // Declares a const pointer to int. 
int const * * const * complexPtr; // A pointer to const pointer to pointer to const int 

Cuando el tipo está escrito con un líder const, la const se maneja como si fue escrito después del primer tipo , entonces const T* se convierte en T const *.

void someFunc2(int * arg); 

por lo tanto, no es redundante, ya que someFunc2 puede cambiar el contenido de arg, mientras someFunc1 no. void someFunc3(int * const arg); sería redundante (y ambiguo) aunque

Cuestiones relacionadas