2009-11-12 9 views
24

Sé que hay pocas preguntas acerca de const correctness donde se indica que la declaración de una función y su definición no necesitan acordar parámetros de valor. Esto se debe a que la consistencia de un parámetro de valor solo importa dentro de la función. Esto está bien:Corrección de const para los parámetros de valor

// header 
int func(int i); 

// cpp 
int func(const int i) { 
    return i; 
} 

¿Está haciendo esto realmente una mejor práctica? Porque nunca he visto a nadie hacerlo. He visto esta cita (no estoy seguro de la fuente) en otros lugares esto se ha discutido:

"In fact, to the compiler, the function signature is the same whether you include this const in front of a value parameter or not."

"Avoid const pass-by-value parameters in function declarations. Still make the parameter const in the same function's definition if it won't be modified."

El segundo párrafo dice que no pone la const en la declaración. Supongo que esto se debe a que la consistencia de un parámetro de valor no tiene sentido como parte de una definición de interfaz. Es un detalle de implementación.

Según esta recomendación, ¿también se recomienda para los valores de puntero de los parámetros del puntero? (No tiene sentido en un parámetro de referencia, puesto que no se puede volver a asignar una referencia.)

// header 
int func1(int* i); 
int func2(int* i); 

// cpp 
int func1(int* i) { 
    int x = 0; 

    *i = 3; // compiles without error 
    i = &x; // compiles without error 

    return *i; 
} 
int func2(int* const i) { 
    int x = 0; 

    *i = 3; // compiles without error 
    i = &x; // compile error 

    return *i; 
} 

Resumen: Haciendo parámetros de valor es útil para capturar algunos errores lógicos. ¿Es una mejor práctica? ¿Vas al extremo de dejar la const fuera del archivo de cabecera? ¿Es tan útil para establecer valores de puntero? ¿Por qué o por qué no?

Algunas referencias:

C++ const keyword - use liberally? Use of 'const' for function parameters

Un ejemplo de cuando los parámetros de valor const son útiles:

bool are_ints_equal(const int i, const int j) { 
    if (i = j) { // without the consts this would compile without error 
     return true; 
    } else { 
     return false; 
    } 
    // return i = j; // I know it can be shortened 
} 
+0

Se llama la "si (i = j)" error en este caso, pero no recoge todas las tales errores, así que no me entusiasmaría demasiado con esa lógica en particular (ya que puedes cometer el mismo error con las variables). Incluso sin la const, tu compilador debería advertirte sobre esto si le dices que quieres advertencias. – nobar

+0

El punto de entusiasmarse con 'if (i = j)' es darse cuenta de que los parámetros del valor de const no son solo de pelusa. El ejemplo de Michael Burr es incluso mejor que este. – jmucchiello

+2

En una situación en la que no está cambiando los parámetros de las funciones, debe configurarlos porque A) es más seguro, B) es autodocumentado, y C) es más fácil de depurar. Además, el prototipo y el encabezado deben marcarse const. Es confuso si solo lo hecho en el encabezado de la función. El argumento sobre la creación de una variable temporal dentro de la función es una situación en la que probablemente no necesite declarar los parámetros const. Son mis 2 centavos. –

Respuesta

7

Mi opinión sobre ella:

No es una mala idea, pero el problema es menor y su energía podría ser mejor gastado en otras cosas.

En su pregunta que proporciona un buen ejemplo de cuándo podría atrapar un error, pero en ocasiones también terminan haciendo algo como esto:

void foo(const int count ...) 
{ 
    int temp = count; // can't modify count, so we need a copy of it 
    ++temp; 

    /* ... */ 
} 

Los pros y los contras son menores de cualquier manera.

+3

+1 por decir que no es una mala idea, y por notar que el problema es menor. Pero antes de copiar el parámetro en el interior, simplemente eliminaría la const (excepto quizás si copiara "count" siempre, como principio de no operar en un parámetro, y no solo porque la const lo impide) –

+8

Usualmente cuando Si modifica la variable de esta manera, está cambiando el significado semántico. Por ejemplo: void foo (const int index0based) {const int index1based = index0based + 1;} Podrías llamarlo índice y cambiarlo, pero esto es mucho más claro para el pobre programador de mantenimiento que aparece en 5 años. – Bill

+0

@Bill, excelente punto! –

9

He leído muchas veces que hacen los parámetros de valor en una función const es algo malo porque no es necesario.

Sin embargo, en ocasiones me resulta útil como comprobación de que mi implementación no hace algo que no pretendo (como en el ejemplo al final de su pregunta).

Por lo tanto, aunque no agregue valor a la persona que llama, algunas veces me agrega un pequeño valor como implementador, y no le quita nada a la persona que llama. Así que no veo ningún daño al usarlo.

Por ejemplo, puedo estar implementando una función C que lleva un par de punteros a un búfer, un puntero al inicio y un puntero al final. Voy a poner datos en el búfer, pero quiero asegurarme de no sobrepasar el final. Así que dentro de la función hay un código que incrementará un puntero a medida que le añada datos. Convertir el puntero al final del búfer en un parámetro const asegurará que no codifique un error que aumente accidentalmente el puntero de límite final en lugar del puntero que realmente debería incrementar.

lo tanto una función fillarray con una firma como esta:

size_t fillArray(data_t* pStart, data_t* const pEnd); 

me impedirá accidentalmente incrementar pEnd cuando realmente significa para incrementar pStart. No es una gran cosa, pero estoy bastante seguro de que todos los que han programado durante un período de tiempo en C se han encontrado con ese error.

+0

Excelente. Estaba buscando un buen ejemplo de un valor de puntero const. – jmucchiello

1

Desafortunadamente, algunos compiladores (¡te estoy viendo, Sun CC!) Diferencian incorrectamente entre argumentos declarados const y no declarados, y puedes obtener errores sobre funciones indefinidas.

-2

me gusta corrección const para situaciones como esta:
void foo(const Bar &b) //I know b cannot be changed
{
//do something with b
}

Esto me permite usar b sin temor a modificarlo, pero no tiene que pagar el costo de un constructor de copia.

+8

No estamos hablando de parámetros de referencia. Parámetros de valor solamente – jmucchiello

0

Creo que esto depende de su estilo personal.

No agrega ni resta a lo que los clientes pueden pasar a su función. En esencia, es como una afirmación en tiempo de compilación. Si te ayuda a saber que el valor no cambiará, adelante y hazlo, pero no veo una razón importante para que otros lo hagan.

Una razón por la que quizás no lo haga es que la constidad del parámetro de valor es un detalle de implementación que sus clientes no necesitan saber. Si más tarde (deliberadamente) cambia su función para que realmente cambie ese valor, tendrá que cambiar la firma de su función, lo que obligará a sus clientes a volver a compilar.

Esto es similar a por qué algunas personas recomiendan no tener métodos virtuales públicos (la función de virtualidad es un detalle de implementación que debe ocultarse a los clientes), pero no estoy en ese campo en particular.

+2

Vuelve a leer la pregunta. El archivo de encabezado no tiene const porque, como dices, a la persona que llama no le importa si la implementación modifica una variable local. Esta es una pregunta estrictamente sobre si vale la pena en el lado de la implementación. – jmucchiello

0

Si hay una palabra clave const; significa que el valor de 'i' (que es tipo const) no puede modificarse. Si se cambia el valor de la 'i' en el interior del compilador función foo arrojará error: "

Can not modify const object

Pero cambiar '* i' (es decir, * i = 3;) significa que no va a cambiar el valor de 'i', pero valor de la dirección apuntada por 'i'

en realidad, la función const es apropiado para grandes objetos que no deben ser alterados por función.

0

todos tenemos que desenredar C de otro código ++ de vez en cuando. Y eso el código de C++ de otra persona es un desastre completo por definición: D.

Así que lo primero que siempre hago para descifrarlo (flujo de datos global local &) se pone const en cada definición de variable hasta que el compilador se queja. Esto también significa argumentos const-qualifying value, y realmente ayuda a evitar las variables que se han modificado en el medio de la función sin que yo lo note ...

así que realmente aprecio cuando esa otra persona tiene const todas partes (incluyendo los parámetros de valor): D

Cuestiones relacionadas