c++ - tipos - Const correcto para los parámetros de valor
paso de parametros por nombre (7)
Sé que hay pocas preguntas sobre const correctness donde se afirma 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 esta bien:
// header
int func(int i);
// cpp
int func(const int i) {
return i;
}
¿Hacer esto realmente es una mejor práctica? Porque nunca he visto a nadie hacerlo. He visto esta cita (no estoy seguro de la fuente) en otros lugares se ha discutido esto:
"De hecho, para el compilador, la firma de la función es la misma ya sea que incluya esta const delante de un parámetro de valor o no".
"Evite los parámetros const pass-by-value en declaraciones de funciones. Aún así haga que el parámetro sea const en la definición de la misma función si no se modificará".
El segundo párrafo dice que no pongas 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.
En función de 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 ya que no puede reasignar 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: la creación de parámetros de valor es útil para detectar algunos errores de lógica. ¿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 palabra clave: ¿usar liberalmente? Uso de ''const'' para los parámetros de función
Un ejemplo de cuando los parámetros de valor de 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
}
Creo que esto depende de tu 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.
Desafortunadamente, algunos compiladores (¡te estoy mirando, Sun CC!) Diferencian incorrectamente entre los argumentos declarados const y los no declarados, y puedes obtener errores sobre las funciones no definidas.
He leído muchas veces que hacer parámetros de valor en una función const es algo malo porque no es necesario.
Sin embargo, a veces 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 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 buffer - 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
garantizará que no codifique un error que aumente accidentalmente el puntero del límite final en lugar del puntero que realmente debería incrementar.
Entonces una función fillArray con una firma como esta:
size_t fillArray( data_t* pStart, data_t* const pEnd);
evitará que pEnd
accidentalmente pEnd
cuando realmente 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.
Me gusta la 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 tengo que pagar el costo de un constructor de copia.
Mi opinión sobre esto:
No es una mala idea, pero el problema es menor y tu energía podría gastarse mejor en otras cosas.
En su pregunta, proporcionó un buen ejemplo de cuándo podría detectar un error, pero ocasionalmente también termina 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 en ambos sentidos.
Si hay una palabra clave const presente; significa que el valor de ''i'' (que es tipo const) no puede modificarse. Si el valor de ''i'' se cambia dentro de la función foo, el compilador arrojará el error: "
No se puede modificar el objeto const
Pero cambiar ''* i'' (es decir, * i = 3;) significa que no está cambiando el valor de ''i'', sino el valor de la dirección apuntada por ''i''
En realidad, la función const es apropiada para objetos grandes que no deberían ser alterados por la función.
Todos tenemos que desenredar el código C ++ de otra persona de vez en cuando. Y que el código C ++ de otra persona es un completo desastre por definición: D.
Entonces, lo primero que siempre hago para descifrarlo (flujo de datos local y global) es const
en cada definición 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 ese otro tiene const en todas partes (incluidos los parámetros de valor): D