Pourquoi ssortingng :: compare retourne-t-il un int?

Pourquoi ssortingng::compare renvoie-t-il un int au lieu d’un type plus petit comme short ou char ? Je crois comprendre que cette méthode ne renvoie que -1, 0 ou 1.

Deuxième partie, si je devais concevoir une méthode de comparaison qui compare deux objects de type Foo et que je ne voulais que renvoyer -1, 0 ou 1, l’utilisation de short ou de char serait-elle une bonne idée?

EDIT: J’ai été corrigé, ssortingng::compare ne retourne pas -1, 0 ou 1, il retourne en fait une valeur> 0, <0 ou 0. Merci de me garder en ligne.

Il semble que la réponse soit grossière, il n’y a pas de raison de retourner un type plus petit que int car les valeurs de retour sont “rvalues” et les “rvalues” ne sont pas plus petites que le type int (4 octets). De plus, beaucoup de gens ont fait remarquer que les registres de la plupart des systèmes vont probablement être de taille int , puisque ces registres vont être remplis que vous leur donniez une valeur de 1, 2 ou 4 octets, il n’y a aucun avantage à retourner une valeur inférieure.

EDIT 2: En fait, l’utilisation de types de données plus petits, tels que l’alignement, le masquage, etc., peut induire une surcharge de traitement. Le consensus général est que les plus petits types de données conservent la mémoire lorsque vous travaillez avec beaucoup de données. cas d’un tableau.

J’ai appris quelque chose aujourd’hui, merci encore les gars!

Tout d’abord, la spécification est qu’il retournera une valeur inférieure, égale ou supérieure à 0 , pas nécessairement -1 ou 1 . Deuxièmement, les valeurs de retour sont des valeurs, sujettes à une promotion intégrale, il est donc inutile de retourner quelque chose de plus petit.

En C ++ (comme en C), chaque expression est une valeur ou une valeur. Historiquement, les termes font référence au fait que les lvalues ​​apparaissent à gauche d’une affectation, où les valeurs ne peuvent apparaître qu’à droite. Aujourd’hui, une simple approximation pour les types non-classe est qu’une lvalue a une adresse en mémoire, une rvalue non. Ainsi, vous ne pouvez pas prendre l’adresse d’un rvalue, et les qualificatifs cv (dont la condition “access”) ne s’appliquent pas. En termes C ++, une valeur qui n’a pas de type de classe est une valeur pure, pas un object. La valeur de retour d’une fonction est une valeur, à moins qu’elle n’ait un type de référence. (Les types hors classe qui s’inscrivent dans un registre seront presque toujours renvoyés dans un registre, par exemple, plutôt que dans la mémoire.)

Pour les types de classe, les problèmes sont un peu plus complexes, car vous pouvez appeler des fonctions membres sur une valeur. Cela signifie que les valeurs doivent avoir des adresses pour this pointeur et peuvent être qualifiées cv, car la qualification cv joue un rôle dans la résolution de la surcharge. Enfin, C ++ 11 introduit plusieurs nouvelles distinctions, afin de prendre en charge les références rvalue; ceux-ci sont également applicables principalement aux types de classe.

La promotion intégrale fait référence au fait que lorsque des types intégraux inférieurs à un int sont utilisés comme valeurs dans une expression, dans la plupart des contextes, ils seront promus dans int . Donc même si j’ai une variable déclarée short a, b; , dans l’expression a + b , les deux a et b sont promus dans int avant que l’ajout se produise. De même, si j’écris a < 0 , la comparaison est faite sur la valeur de a , convertie en int . En pratique, il y a très peu de cas où cela fait une différence, au moins sur 2 les compléments de machines où les arithmétiques entières (sauf presque toutes les exotiques, aujourd'hui - je pense que les mainframes Unisys sont les seules exceptions). Pourtant, même sur les machines les plus courantes:

 short a = 1; std::cout << sizeof( a ) << std::endl; std::cout << sizeof( a + 0 ) << std::endl; 

devrait donner des résultats différents: le premier est l’équivalent de sizeof( short ) , le second sizeof( int ) (à cause de la promotion intégrale).

Ces deux questions sont formellement orthogonales; Les rvalues ​​et les lvalues ​​n'ont rien à voir avec la promotion intégrale. Sauf que la promotion intégrale ne concerne que les valeurs et que la plupart (mais pas toutes) les cas où vous utiliseriez une valeur entraînera une promotion intégrale. Pour cette raison, il n'y a vraiment aucune raison de retourner une valeur numérique dans quelque chose de plus petit que int . Il y a même une très bonne raison de ne pas le retourner en tant que type de caractère. Les opérateurs surchargés, tels que << , se comportent souvent différemment pour les types de caractères. Vous ne voulez donc que renvoyer des caractères en tant que types de caractères. (Vous pouvez comparer la différence:

 char f() { return 'a'; } std::cout << f() << std::endl; // displays "a" std::cout << f() + 0 << std::endl; // displays "97" on my machine 

La différence est que dans le second cas, l'addition a provoqué une promotion intégrale, ce qui entraîne une surcharge différente de << à choisir.

Il est intentionnel qu’il ne renvoie pas -1, 0 ou 1.

Cela permet (notez que ce n’est pas pour les chaînes, mais cela s’applique également aux chaînes)

 int compare(int *a, int *b) { return *a - *b; } 

ce qui est beaucoup moins lourd que:

 int compare(int *a, int *b) { if (*a == *b) return 0; if (*a > *b) return 1; return -1; } 

c’est ce que vous devez faire [ou quelque chose du genre] si vous devez retourner -1, 0 ou 1.

Et cela fonctionne aussi pour des types plus complexes:

 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; } 

Dans le cas de la chaîne, nous pouvons faire ceci:

 int compare(const std::ssortingng& a, const std::ssortingng& 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(); } 

int est généralement (c’est-à-dire sur le matériel le plus moderne) un entier de la même taille que le bus système et / ou le cpu enregistre, ce que l’on appelle le mot machine. Par conséquent, int est généralement transmis plus rapidement que les petits types, car il ne nécessite pas d’alignement, de masquage et d’autres opérations.

Les plus petits types existent principalement pour permettre une optimisation de l’utilisation de la RAM pour les tableaux et les structures. Dans la plupart des cas, ils échangent quelques cycles de processeur (sous la forme d’opérations d’alignement) pour une meilleure utilisation de la RAM.

A moins que vous n’ayez besoin d’appliquer votre valeur de retour à un nombre signé ou non d’un centime (char, short…), vous feriez mieux d’utiliser int, ce qui explique pourquoi la bibliothèque standard le fait.

C’est un C-ism.

Lorsque C exigeait des fonctions de type compare , elles renvoyaient toujours un int . C ++ vient de porter ça (malheureusement).

Cependant, le retour d’un int est probablement le moyen le plus rapide, car c’est généralement la taille des registres du système utilisé. (Délibérément vague.)

La méthode ne renvoie pas un entier dans l’ensemble { -1, 0, 1 } ; il peut en fait être n’importe quelle valeur intégrale.

Pourquoi? La principale raison à laquelle je peux penser est que int est censé être la “taille naturelle” de l’architecture; les opérations sur des valeurs de cette taille sont généralement au moins aussi rapides (et dans de nombreux cas plus rapides) que les opérations sur des valeurs plus petites ou plus grandes. Il s’agit donc de permettre à l’implémentation de disposer de suffisamment de temps pour utiliser ce qui est le plus rapide.

Si je devais concevoir une méthode de comparaison qui compare deux objects de type Foo et que je voulais seulement renvoyer -1, 0 ou 1, l’utilisation de short ou de char serait-elle une bonne idée?

Ce serait ok l’idée. Une meilleure façon serait de renvoyer un bool (si vous voulez seulement comparer si égal), ou enum (pour plus d’informations):

 enum class MyResult { EQUAL, LESS, GREATER }; MyResult AreEqual( const Foo &foo1, const Foo & foo2 ) { // calculate and return result } 

Supposons que certaines personnes modifient un code de C en C ++. Ils ont décidé de remplacer strcmp par ssortingng::compare .

Comme strcmp retourne int , il est plus facile de créer une ssortingng::compare return int , en cadeau.

Probablement pour le faire fonctionner plus comme strcmp qui a aussi cet ensemble de valeurs de retour . Si vous vouliez porter le code, il serait probablement plus intuitif d’avoir des remplacements aussi proches que possible.

En outre, la valeur renvoyée n’est pas juste -1 , 0 ou 1 mais <0 , 0 ou >0 .

En outre, comme cela a été mentionné, le retour étant soumis à une promotion intégrale, il n’est pas logique de le réduire.

car une valeur de retour booléenne ne peut être que deux valeurs possibles (true, false) et une fonction de comparaison peut renvoyer trois valeurs possibles (inférieures à, égales, supérieures à).

Mettre à jour

Bien qu’il soit certainement possible de renvoyer un court-circuit signé, si vous souhaitez vraiment implémenter votre propre fonction de comparaison, vous pouvez renvoyer une valeur de quartet ou de struct avec deux booléens.