string :: compareがintを返すのはなぜですか?


102

またはのような小さい型の代わりにをstring::compare返すのはなぜですか?私の理解では、このメソッドは-1、0、または1のみを返します。intshortchar

2番目の部分では、タイプの2つのオブジェクトを比較する比較メソッドを設計していて、Foo-1、0、または1のみを返したい場合、を使用するshortか、char一般的には良いアイデアでしょうか。

編集:私は修正されました。string::compare-1、0、または1を返しません。実際には> 0、<0または0の値を返します。

おおよその答えのようintですが、戻り値は「rvalues」であり、それらの「rvalues」はint型(4バイト)よりも小さくてもメリットがないため、よりも小さい型を返す理由はありません。また、多くの人は、ほとんどのシステムのレジスターはおそらくintいずれにせよサイズが大きくなるだろうと指摘しました。これらのレジスターは、1、2、または4バイトの値を与えるかどうかにかかわらず満たされるため、小さい値。

編集2:実際には、アライメント、マスキングなどの小さなデータ型を使用すると、余分な処理オーバーヘッドが発生する可能性があるようです。一般的なコンセンサスは、配列の場合。

今日は何かを学びました、ありがとうみんな!


これに使用できるより具体的なタイプがあったらもっと良いと思います。Ada95のスタイルで-1、0、1のみを含むもの。
Sachin Kainth 2013年

23
マニュアルstring::compare()あなたは明確に戻り値を述べへのリンクは<0、0、および> 0 -not- -1、0と1である
キャプテンObvlious

6
shortまたはchar代わりに使用する利点は何intですか?ほとんどのアーキテクチャは、関数の戻り値をレジスタに格納し、inta shortやだけでなく、aもレジスタに収まりcharます。char数値型に使用することは常に悪い考えです。特に、符号付きの値が正しく処理されることを保証する必要がある場合はなおさらです。
コーディグレイ

7
キャプテンObvlious、あなたの名前とコメント...
Cody Smith

2
が署名されていないcharプラットフォームでcharは、戻り値がゼロ未満の場合のコードチェックは失敗するため、使用することはお勧めできません。
ミレニアムバグ2013

回答:


113

まず、仕様はそれに等しいか又はより大きい、より小さい値を返すことで0、必ずしも、-1または1。第2に、戻り値は右辺値であり、整数昇格の対象となるため、これよりも小さい値を返すことは意味がありません。

C ++では(Cと同様)、すべての式は右辺値または左辺値のいずれかです。歴史的に、これらの用語は、左辺値が割り当ての左側に表示されるという事実を指しますが、右辺値は右側にのみ表示されます。今日、非クラス型の単純な近似は、左辺値にはメモリ内のアドレスがあるが、右辺値にはないというものです。したがって、右辺値のアドレスを取得することはできず、cv修飾子(「アクセス」条件)は適用されません。C ++の用語では、クラス型を持たない右辺値は純粋な値であり、オブジェクトではありません。関数の戻り値は、参照型がない限り、右辺値です。(レジスタに収まるクラス以外の型は、ほとんどの場合、たとえばメモリではなくレジスタに返されます。)

クラス型の場合、右辺値でメンバー関数を呼び出すことができるため、問題はもう少し複雑です。これはthis 、cv-qualificationがオーバーロードの解決に役割を果たすため、rvalueは実際にはポインターのアドレスを持つ必要があり、cv-qualifiedにすることができることを意味します。最後に、C ++ 11では、右辺値参照をサポートするために、いくつかの新しい違いが導入されています。これらも主にクラス型に適用されます。

整数の昇格とは、式よ​​りも小さい整数型intが式の右辺値として使用される場合、ほとんどのコンテキストで、に昇格されるという事実を指しintます。だから私は、変数を持っている場合でも、宣言short a, b;式では、a + b両方、aおよびbに昇格されているintほかが発生する前に。同様に、を書いたa < 0場合、比較はの値で行われ、aに変換されますint。実際には、これが違いをもたらすケースは非常に少なく、少なくとも2の補数のマシンでは整数演算がラップします(つまり、今日では非常に少数のエキゾチックを除いて、すべて—残りの唯一の例外はUnisysメインフレームだと思います)。それでも、より一般的なマシンでも:

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

異なる結果が得られるはずです。1つ目はと同等 sizeof( short )、2つ目はsizeof( int )(統合昇格のため)

これら2つの問題は形式的には直交しています。右辺値と左辺値は、整数の昇格とは関係ありません。 ...を除いて、整数の昇格は右辺値にのみ適用され、右辺値を使用する場合のほとんど(すべてではない)は、整数の昇格になります。このため、より小さい数値で数値を返す必要はありませんint。これを文字型として返さないのには十分な理由があります。のようなオーバーロードされた演算子は、<<文字タイプに対して異なる動作をすることが多いため、文字を文字タイプとして返​​すだけです。(違いを比較するかもしれません:

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

違いは、2番目のケースでは、追加により積分の昇格が発生し、その結果、異なるオーバーロード<<が選択されることです。


46
あなたがreturn values are rvalues, subject to integral promotionあなたの答えでもっと説明できるなら、それは素晴らしいです。
Alvin Wong

「戻り値は右辺値です...したがって、これよりも小さい値を返す意味はありません」 LIKE IT
masoud

1
@AlvinWong:Cの文字リテラルが文字ではなく整数である理由に対する回答を参照してくださいいくつかの背景情報については。
ジェシーグッド

あなたの編集が加えた素晴らしい説明の後で、これをもう一度+1できるといいのですが。
コーディグレイ

もしそうだっsigned charたら?それはsignedと同じように動作しますかchar、それとも別のタイプですか?
user541686 2013年

41

-1、0、1を返さないように意図されています。

許可します(これは文字列ではありませんが、文字列に同様に適用されます)

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

これは、次の場合よりもずっと面倒ではありません。

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

これは、-1、0、または1を返す必要がある場合に、あなたがしなければならないことです(またはそれらの行に沿って何か)。

そして、それはより複雑な型に対しても機能します:

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

文字列の場合、これを行うことができます:

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

8
最初のcompare関数にはオーバーフローの問題があり、それが(幸いにも)かかりchar*charそれよりも小さい場合は等しく適用されませんint。例えば、場合*aであるMAX_INT*bされ-1、その後*a - *bUBですが、実装を選択したが、ほぼ確実にし、結果をその動作を定義する場合は負です。
スティーブジェソップ2013年

1
最後の例の問題:… をlength()返すsize_t可能性がありintます…
F'x

ええ、文字列が2GBを超える場合は問題になるかもしれません。私は1 GBの長い文字列を、FIFOに一度格納するためのテストケースとして実行しました。しかし、確かに、Base64としてエンコードされたMPEGを含む文字列などを扱っている誰かがその問題に
遭遇

@MatsPeterssonは、「なぜintを返すのですか?」
F'x

まあ、それはヒステリックだと確信しています-歴史的な理由を意味します-そしておそらくstrcmp / memcmpや他の比較型操作と互換性があるようにするためです。
Mats Petersson 2013年

25

intは通常(ほとんどの最新のハードウェアを意味します)、システムバスやCPUレジスタと同じサイズの整数で、マシンワードと呼ばれます。したがって、整列、マスキング、およびその他の操作を必要としないため、intは通常、小さい型よりも速く渡されます。

小さい型は、主に配列と構造体のRAM使用を最適化するために存在します。ほとんどの場合、RAM使用率を向上させるために、CPUサイクルを数回(調整操作の形で)交換します。

戻り値を証明書サイズ(char、short…)の符号付きまたは符号なしの数値にする必要がある場合を除いて、intを使用するほうがよいため、標準ライブラリがそれを行います。


物事のハードウェア側を意味のある方法で説明する素晴らしい方法。
Ogre Psalm33 2013年

10

それはC主義です。

Cがcompare-type関数を必要とした場合、それらは常にを返しましたint。C ++はそれを先に進めました(残念ながら)。

ただし、を返すことintは、実際には使用中のシステムのレジスターのサイズであるため、おそらく最も高速な方法です。(意図的に曖昧です。)


1
実はshortおよびchar例えば、パフォーマンスのペナルティを課すことができる255+7ための異なる値があるcharintは必ずしも単純に格納することはできません正しい実装ので、charどこintにその意味を手渡しの世話をせずに行くことができます。コンパイラーは、これがもたらす非効率を必ずしも最適化するわけではありません。
Jack Aidley、2013年

10

このメソッドは、実際にはセット内の整数を返しません{ -1, 0, 1 }。実際には任意の整数値にすることができます。

どうして?私が考えることができる主な理由は、それintがアーキテクチャの「自然なサイズ」の値であることになっているということです。このサイズの値の操作は、通常、小さい値または大きい値の操作よりも少なくとも同じくらい高速です(多くの場合、高速です)。したがって、これは、実装が最速のものを使用するのに十分なスラックを許可する場合です。


4

Foo型の2つのオブジェクトを比較する比較メソッドを設計し、-1、0、または1のみを返したい場合は、shortまたはcharを使用するのが一般的に良いでしょうか?

大丈夫だと思います。より良い方法は、ブール値(等しい場合にのみ比較したい場合)または列挙型(詳細)を返すことです。

enum class MyResult
{
  EQUAL,
  LESS,
  GREATER
};

MyResult AreEqual( const Foo &foo1, const Foo & foo2 )
{
  // calculate and return result
}

3
「それはいいアイデアだろう」。その根拠はありますか?
jrok 2013年

4

一部の人々がコードをCからC ++に変更するとします。彼らはに置き換えることにしましstrcmpstring::compare

strcmpが返ってくるので、プレゼントとしても返却しintやすくなります。string::compareint


2

おそらく、strcmpこの戻り値のセットも持っているように機能させるためです。コードを移植したい場合は、できるだけ近くで切断する置換を使用すると、より直感的になります。

また、戻り値は単に-10またはでは1なく<00または>0です。

また、前述のように、リターンは統合的なプロモーションの対象であるため、小さくすることは意味がありません。


-1

ブール値の戻り値は2つの値(true、false)のみであり、compare関数は3つの可能な値(より小さい、等しい、より大きい)を返すことができるためです。

更新

符号付きshortを返すことは確かに可能ですが、実際に独自の比較関数を実装したい場合は、2つのブール値でニブルまたは構造体の値を返すことができます。


7
質問のどこにも、ブール型を返すことについて何も書かれていません。実際、彼は具体的に提案shortchar、の代替案としてint
コーディグレイ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.