102

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

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

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

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

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

今日は何かを学びました。ありがとうございました。

4

9 に答える 9

113

0まず、仕様では、必ずしも-1またはではなく、より小さい、等しい、またはより大きい値を返します1。第二に、戻り値は汎整数拡張の対象となる右辺値であるため、小さいものを返す意味はありません。

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

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

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

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

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番目のケースでは、加算によって汎整数拡張が発生し、その結果、<<選択されるの異なる過負荷が発生することです。

于 2013-03-11T12:30:20.990 に答える
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();
}
于 2013-03-11T12:39:02.703 に答える
25

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

小さいタイプは、主に配列と構造体のRAM使用量を最適化するために存在します。ほとんどの場合、RAMの使用量を増やすために(アライメント操作の形で)数CPUサイクルを交換します。

戻り値をcentainサイズ(char、short…)の符号付きまたは符号なしの数値にする必要がない限り、intを使用する方が適切です。これが、標準ライブラリがそれを行う理由です。

于 2013-03-11T15:08:31.177 に答える
10

それはC-ismです。

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

intただし、一般的に使用中のシステムのレジスタのサイズであるため、を返すのが現実的にはお​​そらく最速の方法です。(意図的に曖昧です。)

于 2013-03-11T12:31:13.310 に答える
10

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

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

于 2013-03-11T12:32:23.340 に答える
5

タイプFooの2つのオブジェクトを比較するcompareメソッドを設計し、-1、0、または1のみを返したい場合、shortまたはcharを使用することは一般的に良い考えですか?

それは大丈夫だろう。より良い方法は、bool(等しい場合にのみ比較したい場合)またはenum(詳細について)を返すことです。

enum class MyResult
{
  EQUAL,
  LESS,
  GREATER
};

MyResult AreEqual( const Foo &foo1, const Foo & foo2 )
{
  // calculate and return result
}
于 2013-03-11T12:29:37.223 に答える
4

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

strcmp返品できるので、プレゼントとして返品intしやすいです。string::compareint

于 2013-03-11T12:33:02.840 に答える
2

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

また、戻り値は-1, 0orだけで1なく<0, 0or>0です。

また、前述したように、リターンはインテグラル プロモーションの対象となるため、小さくしても意味がありません。

于 2013-03-11T12:31:41.687 に答える
-1

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

アップデート

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

于 2013-03-11T12:39:37.367 に答える