str - toupper c++ library
¿Por qué string:: compare return an int? (9)
¿Por qué string::compare
devuelve un int en lugar de un tipo más pequeño como short
o char
? Según entiendo, este método solo devuelve -1, 0 o 1.
La segunda parte, si tuviera que diseñar un método de comparación que comparara dos objetos de tipo Foo
y solo quisiera devolver -1, 0 o 1, ¿sería una buena idea usar short
o char
?
EDITAR: He sido 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 más o menos, no hay razón para devolver un tipo más pequeño que int porque los valores de retorno son "valores r" y esos "valores r" 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 sean de tamaño int de todos modos, ya que estos registros se llenarán si les das un valor de 1, 2 o 4 bytes, no hay una ventaja real para regresar. un valor más pequeño.
EDIT 2: De hecho, parece que puede haber una sobrecarga de procesamiento adicional al usar tipos de datos más pequeños como alineación, enmascaramiento, etc. El consenso general es que existen tipos de datos más pequeños para conservar en la memoria cuando se trabaja con una gran cantidad de datos, como en caso de una matriz.
Aprendí algo hoy, gracias otra vez chicos!
si tuviera que diseñar un método de comparación que comparara dos objetos de tipo Foo y solo quisiera devolver -1, 0 o 1, ¿sería una buena idea usar corto o char?
Estaría bien idea. Una forma mejor sería devolver un bool (si solo desea comparar si es igual), o enum (para obtener más información):
enum class MyResult
{
EQUAL,
LESS,
GREATER
};
MyResult AreEqual( const Foo &foo1, const Foo & foo2 )
{
// calculate and return result
}
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 por la que puedo pensar es que se supone que int
es el valor de "tamaño natural" para la arquitectura; las operaciones en valores de este tamaño suelen ser al menos tan rápidas (y en muchos casos más rápidas) que las operaciones en valores más pequeños o más grandes. Así que este es un caso de permitir la implementación suficiente holgura para usar lo que sea más rápido.
Es intencional que no devuelva -1, 0 o 1.
Permite (tenga en cuenta que esto no es para cadenas, pero se aplica por igual a cadenas)
int compare(int *a, int *b)
{
return *a - *b;
}
que es mucho menos engorroso que:
int compare(int *a, int *b)
{
if (*a == *b) return 0;
if (*a > *b) return 1;
return -1;
}
que es lo que tendrías que hacer [o algo así] si tienes que devolver -1, 0 o 1.
Y también funciona para tipos más complejos:
class Date
{
int year;
int month;
int day;
}
int compare(const Date &a, const Date &b)
{
if (a.year != b.year) return a.year - b.year;
if (a.month != b.month) return a.month - b.month;
return a.day - b.day;
}
En el caso de cuerdas, podemos hacer esto:
int compare(const std::string& a, const std::string& b)
{
int len = min(a.length(), b.length());
for(int i = 0; i < len; i++)
{
if (a[i] != b[i]) return a[i] - b[i];
}
// We only get here if the string is equal all the way to one of them
// ends. If the length isn''t equal, "longest" wins.
return a.length() - b.length();
}
Primero, la especificación es que devolverá un valor menor que, igual o mayor que 0
, no necesariamente -1
o 1
. En segundo lugar, los valores de retorno 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 valor r o un valor l. Históricamente, los términos se refieren al hecho de que los valores l aparecen a la izquierda de una tarea, 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 valor l tiene una dirección en la memoria, un valor r no. Por lo tanto, no puede tomar la dirección de un valor r, y los cv-calificadores (que condicionan "acceso") no se aplican. En términos de C ++, un valor r que no tiene un tipo de clase es un valor puro, no un objeto. El valor de retorno de una función es un valor r, a menos que tenga un tipo de referencia. (Los tipos que no son de clase y que se ajustan a 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 las funciones miembro en un valor r. Esto significa que los valores reales de hecho deben tener direcciones, para this
puntero, y pueden ser calificados como cv, ya que la calificación cv juega un rol en la resolución de sobrecarga. Finalmente, C ++ 11 introduce varias distinciones nuevas, para admitir referencias de valores; estos, también, son principalmente aplicables a los tipos de clase.
La promoción integral se refiere al hecho de que cuando los tipos integrales más pequeños que un int
se usan como valores en una expresión, en la mayoría de los contextos, serán promovidos a int
. Entonces, incluso si tengo una variable declarada short a, b;
, en la expresión a + b
, tanto a
como b
se promueven a int
antes de que ocurra la suma. De manera similar, si escribo a < 0
, la comparación se realiza sobre el valor de a
, convertido a int
. En la práctica, hay muy pocos casos en los que esto hace la diferencia, al menos en máquinas de complementos de 2 donde se envuelven aritmética de enteros (es decir, todos menos algunos 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:
short a = 1;
std::cout << sizeof( a ) << std::endl;
std::cout << sizeof( a + 0 ) << std::endl;
debería dar resultados diferentes: el primero es el equivalente de sizeof( short )
, el segundo sizeof( int )
(debido a la promoción integral).
Estos dos problemas son formalmente ortogonales; Los valores y valores no tienen nada que ver con la promoción integral. Excepto ... la promoción integral solo se aplica a los valores r, y la mayoría (pero no todos) de los casos en los que usaría un valor r dará como resultado una promoción integral. Por esta razón, realmente no hay razón para devolver un valor numérico en algo más pequeño que int
. Incluso hay una muy buena razón para no devolverlo como un tipo de personaje. 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:
char f() { return ''a''; }
std::cout << f() << std::endl; // displays "a"
std::cout << f() + 0 << std::endl; // displays "97" on my machine
La diferencia es que en el segundo caso, la adición ha provocado que se produzca la promoción integral, lo que da como resultado una sobrecarga diferente de <<
para ser elegido.
Probablemente para hacer que funcione más como strcmp
que también tiene este conjunto de valores de retorno . Si quisieras codificar el puerto, probablemente sería más intuitivo tener reemplazos que se escindan lo más cerca posible.
Además, el valor de retorno no es solo -1
, 0
o 1
sino <0
, 0
o >0
.
Además, como se mencionó ya que la devolución está sujeta a promoción integral , no tiene sentido que sea más pequeña.
Supongamos que algunas personas cambian un código de C a C ++. Decidieron reemplazar strcmp
por una string::compare
.
Dado que strcmp
devuelve int
, es más fácil strcmp
string::compare
return int
, como un regalo.
int es generalmente (es decir, en la mayoría de los equipos modernos) un número entero del mismo tamaño que el bus del sistema y / o la CPU registra, lo que se denomina la palabra máquina. Por lo tanto, int se pasa generalmente más rápido que los tipos más pequeños, ya que 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) para un mejor uso de la RAM.
A menos que necesite forzar su valor de retorno para que sea un número firmado o sin firmar de un tamaño centain (char, short ...) le conviene usar int, que es la razón por la cual la biblioteca estándar lo hace.
porque un valor de retorno booleano solo puede tener 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 corto firmado, si realmente desea implementar su propia función de comparación, puede devolver un valor de nibble o struct con dos booleanos.
Es un C-ismo.
Cuando C requirió compare
-type functions, siempre devolvieron un int
. C ++ acaba de llevar 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)