C++ コードで `int` を使用する理由はまだありますか? [重複] 質問する

C++ コードで `int` を使用する理由はまだありますか? [重複] 質問する

Google スタイル ガイドなど、多くのスタイル ガイドでは、intたとえば配列のインデックスを作成するときに をデフォルトの整数として使用することを推奨しています。64 ビット プラットフォームの台頭により、ほとんどの場合 はint32 ビットのみとなり、プラットフォームの自然な幅ではなくなります。結果として、単純に同じである以外に、その選択を維持する理由は見当たりません。次のコードをコンパイルすると、それが明らかになります。

double get(const double* p, int k) {
  return p[k];
}

これは次のようにコンパイルされます

movslq %esi, %rsi
vmovsd (%rdi,%rsi,8), %xmm0
ret

最初の命令は 32 ビットの整数を 64 ビットの整数に変換します。

コードが次のように変換された場合

double get(const double* p, std::ptrdiff_t k) {
  return p[k];
}

生成されたアセンブリは

vmovsd (%rdi,%rsi,8), %xmm0
ret

これは、CPU が よりstd::ptrdiff_tも の方が使いやすいことを明確に示していますint。多くの C++ ユーザーが に移行していますstd::size_tが、モジュロ動作が本当に必要な場合を除いて、符号なし整数は使いたくありません2^n

ほとんどの場合、int未定義の動作や符号付き整数のオーバーフローにより、コンパイラーはインデックスを処理するループ内で内部的に anyintを a に昇格できるため、 を使用するとパフォーマンスが低下しませんが、上記から、コンパイラーが をうまく扱えないことは明らかです。また、よりも大きな整数を扱わなければならない場合にオーバーフローに陥る人が増えていることを最近はよく見かけますが、64 ビット プラットフォームで を使用すると、オーバーフローが発生する可能性が低くなります。std::ptrdiff_tintstd::ptrdiff_tint2^31 - 1

私が見た限りでは、 を際立たせている唯一の点は、 などのリテラルが であるintという事実のようですが、 をデフォルトの整数として に移行しても問題が発生する可能性は低いと思います。5intstd::ptrdiff_t

私は、自分の小さな会社で書かれたすべてのコードに対して、整数を事実上の標準にしようとしていますstd::ptrdiff_t。それが悪い選択になる理由はあるのでしょうか?

追伸:名前が醜いという事実には同意します。それが、見た目を少し良くするstd::ptrdiff_tために typedef した理由です。il::int_t

PS: 多くの人がデフォルトの整数として を使用することを勧めていることはわかっているのでstd::size_t、符号なし整数をデフォルトの整数として使用したくないということを明確にしておきたいと思います。STL で をデフォルトの整数として使用することは、std::size_tBjarne Stroustrup と標準委員会がビデオで認めているように間違いでした。インタラクティブパネル: 何でも聞いてください42:38 と 1:02:50 の時刻。

追伸:パフォーマンスの点では、私が知っているどの 64 ビット プラットフォームでも、+とはどちらも同じようにコンパイルされます。したがって、速度に違いはありません。コンパイル時の定数で割ると、速度は同じです。何も知らないときに除算する場合にのみ、64 ビット プラットフォームで 32 ビット整数を使用するとパフォーマンスがわずかに向上します。ただし、このケースは非常にまれであるため、 から離れる選択肢はないと思います。ベクトル化されたコードを扱う場合、ここでは明らかな違いがあり、小さいほど良いのですが、それは別の話であり、 に固執する理由はありません。そのような場合は、C++ の固定サイズ型を使用することをお勧めします。-*intstd::ptrdiff_ta/bbstd::ptrdiff_tint

ベストアンサー1

C++ コア ガイドラインで何を使用するかについて議論がありました。

https://github.com/isocpp/CppCoreGuidelines/pull/1115

Herb Sutter は、gsl::indexが追加される予定 (将来的には になる可能性ありstd::index) であり、 として定義される予定であると書いていますptrdiff_t

hsutter は 2017 年 12 月 26 日にコメントしました •

(このメモにコメントとフィードバックを提供してくれた多くの WG21 の専門家に感謝します。)

GSLに次のtypedefを追加します

namespace gsl { using index = ptrdiff_t; }

gsl::indexすべてのコンテナのインデックス/サブスクリプト/サイズに推奨されます。

根拠

ガイドラインでは、添字/インデックスに符号付き型を使用することを推奨しています。ES.100 から ES.107 を参照してください。C++ では、配列の添字にすでに符号付き整数が使用されています。

私たちは、シンプルで自然、高い警告レベルでも警告が出ず、単純なコードについての「落とし穴」の脚注を書かなくても済む、「新しいクリーンでモダンなコード」の書き方を人々に教えたいと思っています。

や とindex競合する のような短くて採用可能な単語がなければ、人々は依然として やを使用し、バグを抱えることになります。たとえば、広く使用されているプラ​​ットフォームで 32 ビット サイズのバグがあるや を書き、まったく動作しない を書きます。真顔で教えることはできないと思いますし、人々がそれを受け入れるとも思えません。intautointautofor(int i=0; i<v.size(); ++i)for(auto i=0; i<v.size(); ++i)for(auto i=v.size()-1; i>=0; ++i)for(ptrdiff_t i = ...

飽和演算型があれば、それを使用するかもしれません。そうでない場合、最良の選択肢は です。ptrdiff_tこれは、飽和演算 unsigned 型のほぼすべての利点を備えていますが、 だけが、今日の STL コンテナーの で(および でも同様)ptrdiff_t一般的なループ スタイルfor(ptrdiff_t i=0; i<v.size(); ++i)によって符号付き/符号なしの不一致が発生するという欠点があります。(将来の STL で size_type が signed に変更された場合、この最後の欠点も解消されます。)i<v.size()i!=v.size()

しかし、人々に を日常的に書くように教えようとするのは絶望的 (そして恥ずかしい) でしょうfor (ptrdiff_t i = ... ; ... ; ...)。(ガイドラインでも現在 を 1 か所でしか使用しておらず、それはインデックス作成とは関係のない「悪い」例です。)

したがって、の typedef としてgsl::index(これは後で として検討するために提案できます)を提供する必要があります。そうすれば、 に対して日常的に記述することを人々にうまく (そして恥ずかしくなく) 教えることができるでしょう。std::indexptrdiff_t(index i = ... ; ... ; ...)

なぜ人々に書くように言わないのですかptrdiff_t?なぜなら、C++ ではそうしなければならないと人々に伝えるのは恥ずかしいことであり、たとえ伝えたとしても、人々はそうしないだろうと私たちは考えているからです。とptrdiff_tと比べると、書き方が醜すぎて採用できません。 名前を追加する目的は、正しいサイズの符号付き型をできるだけ簡単に、魅力的に使用できるようにすることです。autointindex

編集: ハーブ・サッターからのさらなる根拠

十分な大きさですかptrdiff_t?ptrdiff_tはい。2つの反復子を減算すると、difference_type に収まる必要があるため、標準のコンテナーでは、 で表すことができる数を超える要素を持つことがすでに要求されています。

しかし、メモリ アドレス空間のサイズの半分よりも大きく、 で表現できるよりも多くの要素を持つまたはptrdiff_tの組み込み配列がある場合、 は本当に十分な大きさでしょうか?charbyteptrdiff_tはい。C++ では、配列の添え字に既に符号付き整数が使用されています。そのため、index組み込み配列を含むほとんどの用途で、 をデフォルト オプションとして使用します。(アドレス空間の半分よりも大きく、要素が である配列または配列のような型という極めてまれなケースに遭遇し、sizeof(1)切り捨ての問題を回避することに注意している場合は、size_tその非常に特殊なコンテナーのみにインデックスを付けるために を使用してください。このような厄介なケースは実際には非常にまれであり、発生した場合でも、ユーザー コードによって直接インデックス付けされることはほとんどありません。たとえば、これらは通常、システムの割り当てを引き継いでユーザーが使用する個々の小さな割り当てを分割するメモリ マネージャー、または独自のインターフェイスを提供する MPEG または同様のもので発生します。どちらの場合も、 はsize_tメモリ マネージャーまたは MPEG クラスの実装内で内部的にのみ必要になります。)

おすすめ記事