¿Por qué string::compare
devuelve un en int
lugar de un tipo más pequeño como short
o char
? Tengo entendido que este método solo devuelve -1, 0 o 1.
Segunda parte, si tuviera que diseñar un método de comparación que compare dos objetos de tipo Foo
y solo quisiera devolver -1, 0 o 1, ¿ sería una buena idea usar short
o en char
general?
EDITAR: Me han corregido, string::compare
no devuelve -1, 0 o 1, de hecho devuelve un valor> 0, <0 o 0. Gracias por mantenerme en línea, chicos.
Parece que la respuesta es aproximadamente, no hay razón para devolver un tipo más pequeño que int
porque los valores devueltos son "rvalues" y esos "rvalues" no se benefician de ser más pequeños que el tipo int (4 bytes). Además, muchas personas señalaron que los registros de la mayoría de los sistemas probablemente serán de tamaño grande de int
todos modos, ya que estos registros se llenarán si les da un valor de 1, 2 o 4 bytes, no hay una ventaja real en devolver un menor valor.
EDICIÓN 2: De hecho, parece que puede haber una sobrecarga de procesamiento adicional cuando se utilizan tipos de datos más pequeños, como alineación, enmascaramiento, etc. El consenso general es que los tipos de datos más pequeños existen para conservar la memoria cuando se trabaja con muchos datos, como en el caso de una matriz.
Aprendí algo hoy, ¡gracias de nuevo chicos!
string::compare()
su enlace establece claramente que el valor de retorno es <0, 0 y> 0 -no- -1, 0 y 1.short
o enchar
lugar deint
? La mayoría de las arquitecturas almacenarán el valor de retorno de una función en un registro, y unaint
encajará en un registro tan bien como unashort
ochar
. Y usarchar
para tipos numéricos siempre es una mala idea, especialmente cuando necesita garantizar que los valores firmados se manejen correctamente.char
sería una mala idea, ya que la verificación del código para el valor de retorno si es menor que cero fallará en plataformas dondechar
no esté firmado.Respuestas:
Primero, la especificación es que devolverá un valor menor, igual o mayor que
0
, no necesariamente-1
o1
. En segundo lugar, los valores devueltos son valores r, sujetos a promoción integral, por lo que no tiene sentido devolver algo más pequeño.En C ++ (como en C), cada expresión es un rvalue o un lvalue. Históricamente, los términos se refieren al hecho de que los valores l aparecen a la izquierda de una asignación, mientras que los valores r solo pueden aparecer a la derecha. Hoy en día, una aproximación simple para los tipos que no son de clase es que un lvalue tiene una dirección en la memoria, un rvalue no. Por lo tanto, no puede tomar la dirección de un rvalue y los calificadores cv (cuya condición es "acceso") no se aplican. En términos de C ++, un rvalue que no tiene tipo de clase es un valor puro, no un objeto. El valor de retorno de una función es un rvalue, a menos que tenga un tipo de referencia. (Los tipos que no son de clase que caben en un registro casi siempre se devolverán en un registro, por ejemplo, en lugar de en la memoria).
Para los tipos de clase, los problemas son un poco más complejos, debido al hecho de que puede llamar a funciones miembro en un rvalue. Esto significa que los rvalues deben tener direcciones, para el
this
puntero, y pueden estar calificados cv, ya que la calificación cv juega un papel en la resolución de sobrecargas. Finalmente, C ++ 11 introduce varias distinciones nuevas, con el fin de admitir referencias rvalue; estos también son principalmente aplicables a tipos de clases.La promoción integral se refiere al hecho de que cuando
int
se utilizan tipos integrales menores que an como valores r en una expresión, en la mayoría de los contextos, se promoverán aint
. Entonces, incluso si tengo una variable declaradashort a, b;
, en la expresióna + b
, se promueven ambosa
y antes de que ocurra la adición. De manera similar, si escribo , la comparación se realiza sobre el valor de , convertido a un . En la práctica, hay muy pocos casos en los que esto hace una diferencia, al menos en máquinas de complementos de 2 donde la aritmética de enteros se ajusta (es decir, todos menos unos pocos exóticos, hoy en día, creo que los mainframes de Unisys son las únicas excepciones que quedan). Aún así, incluso en las máquinas más comunes:b
int
a < 0
a
int
debe dar resultados diferentes: el primero es el equivalente de
sizeof( short )
, el segundosizeof( int )
(por promoción integral).Estos dos temas son formalmente ortogonales; rvalues y lvalues nada tienen que ver con la promoción integral. Excepto ... la promoción integral solo se aplica a rvalues, y la mayoría (pero no todos) de los casos en los que usaría un rvalue resultará en una promoción integral. Por esta razón, realmente no hay ninguna razón para devolver un valor numérico en algo menor que
int
. Incluso hay una muy buena razón para no devolverlo como tipo de carácter. Los operadores sobrecargados, como<<
, a menudo se comportan de manera diferente para los tipos de caracteres, por lo que solo desea devolver caracteres como tipos de caracteres. (Puede comparar la diferencia:La diferencia es que en el segundo caso, la adición ha provocado que se produzca una promoción integral, lo que da como resultado una sobrecarga diferente de
<<
elegida.fuente
return values are rvalues, subject to integral promotion
en su respuesta.signed char
? ¿Se comportaría igual que una firmadachar
o sería de un tipo diferente?Es intencional que no devuelva -1, 0 o 1.
Permite (tenga en cuenta que esto no es para cadenas, pero se aplica igualmente a cadenas)
que es mucho menos engorroso que:
que es lo que tendrías que hacer [o algo por el estilo] si tienes que devolver -1, 0 o 1.
Y también funciona para tipos más complejos:
En el caso de la cadena, podemos hacer esto:
fuente
compare
función tiene problemas con el desbordamiento que (afortunadamente) no se aplican igualmente si tomachar*
ychar
es más pequeño queint
. Por ejemplo, si*a
esMAX_INT
y*b
es-1
entonces*a - *b
es UB, pero si la implementación elige definir su comportamiento, el resultado es casi seguro que es negativo.length()
devuelve asize_t
, que puede ser mayor queint
…int es generalmente (es decir, en la mayoría de hardware moderno) un número entero del mismo tamaño que el bus del sistema y / o los registros de la cpu, lo que se denomina palabra máquina. Por lo tanto, int generalmente se transmite más rápido que los tipos más pequeños, porque no requiere alineación, enmascaramiento ni otras operaciones.
Los tipos más pequeños existen principalmente para permitir la optimización del uso de RAM para matrices y estructuras. En la mayoría de los casos, intercambian algunos ciclos de CPU (en forma de operaciones de alineación) por un mejor uso de la RAM.
A menos que necesite exigir que su valor de retorno sea un número firmado o sin firmar de un tamaño centain (char, short…), es mejor usar int, por lo que la biblioteca estándar lo hace.
fuente
Es un C-ismo.
Cuando C requería
compare
funciones de tipo -tipo, siempre devolvían unint
. C ++ simplemente llevó eso adelante (desafortunadamente).Sin embargo, devolver un
int
es probablemente la forma más rápida, ya que generalmente es el tamaño de los registros del sistema en uso. (Deliberadamente vago.)fuente
short
ychar
puede imponer penalizaciones de rendimiento, por ejemplo,255+7
tiene un valor diferente para aychar
an,int
por lo que una implementación correcta no necesariamente puede simplemente almacenar achar
dondeint
puede ir sin ocuparse de entregar su semántica. Los compiladores no necesariamente optimizarán la ineficiencia que esto impone.El método en realidad no devuelve un número entero en el conjunto
{ -1, 0, 1 }
; en realidad, puede ser cualquier valor integral.¿Por qué? La razón principal en la que puedo pensar es que
int
se supone que es el valor de "tamaño natural" para la arquitectura; las operaciones con valores de este tamaño suelen ser al menos tan rápidas (y en muchos casos más rápidas) que las operaciones con valores más pequeños o más grandes. Así que este es un caso de permitir que la implementación sea lo suficientemente floja para usar lo que sea más rápido.fuente
Estaría bien la idea. Una mejor manera sería devolver un bool (si solo desea comparar si es igual), o enum (para obtener más información):
fuente
Supongamos que algunas personas están cambiando un código de C a C ++. Decidieron reemplazar
strcmp
astring::compare
.Desde las
strcmp
devolucionesint
, es más fácilstring::compare
devolverlasint
, como regalo.fuente
Probablemente para que funcione más como lo
strcmp
que también tiene este conjunto de valores de retorno . Si quisiera portar el código, probablemente sería más intuitivo tener reemplazos que se escinden lo más cerca posible.Además, el valor de retorno no es solo
-1
,0
o1
sino<0
,0
o>0
.Asimismo, como se mencionó dado que la devolución está sujeta a promoción integral no tiene sentido hacerla más pequeña.
fuente
porque un valor de retorno booleano solo puede ser dos valores posibles (verdadero, falso) y una función de comparación puede devolver tres valores posibles (menor que, igual, mayor que).
Actualizar
Aunque ciertamente es posible devolver un short firmado, si realmente desea implementar su propia función de comparación, puede devolver un valor nibble o struct con dos valores booleanos.
fuente
short
ychar
como alternativas aint
.