Google スタイル ガイドなど、多くのスタイル ガイドでは、int
たとえば配列のインデックスを作成するときに をデフォルトの整数として使用することを推奨しています。64 ビット プラットフォームの台頭により、ほとんどの場合 はint
32 ビットのみとなり、プラットフォームの自然な幅ではなくなります。結果として、単純に同じである以外に、その選択を維持する理由は見当たりません。次のコードをコンパイルすると、それが明らかになります。
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_t
int
std::ptrdiff_t
int
2^31 - 1
私が見た限りでは、 を際立たせている唯一の点は、 などのリテラルが であるint
という事実のようですが、 をデフォルトの整数として に移行しても問題が発生する可能性は低いと思います。5
int
std::ptrdiff_t
私は、自分の小さな会社で書かれたすべてのコードに対して、整数を事実上の標準にしようとしていますstd::ptrdiff_t
。それが悪い選択になる理由はあるのでしょうか?
追伸:名前が醜いという事実には同意します。それが、見た目を少し良くするstd::ptrdiff_t
ために typedef した理由です。il::int_t
PS: 多くの人がデフォルトの整数として を使用することを勧めていることはわかっているのでstd::size_t
、符号なし整数をデフォルトの整数として使用したくないということを明確にしておきたいと思います。STL で をデフォルトの整数として使用することは、std::size_t
Bjarne Stroustrup と標準委員会がビデオで認めているように間違いでした。インタラクティブパネル: 何でも聞いてください42:38 と 1:02:50 の時刻。
追伸:パフォーマンスの点では、私が知っているどの 64 ビット プラットフォームでも、+
とはどちらも同じようにコンパイルされます。したがって、速度に違いはありません。コンパイル時の定数で割ると、速度は同じです。何も知らないときに除算する場合にのみ、64 ビット プラットフォームで 32 ビット整数を使用するとパフォーマンスがわずかに向上します。ただし、このケースは非常にまれであるため、 から離れる選択肢はないと思います。ベクトル化されたコードを扱う場合、ここでは明らかな違いがあり、小さいほど良いのですが、それは別の話であり、 に固執する理由はありません。そのような場合は、C++ の固定サイズ型を使用することをお勧めします。-
*
int
std::ptrdiff_t
a/b
b
std::ptrdiff_t
int
ベストアンサー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 ビット サイズのバグがあるや を書き、まったく動作しない を書きます。真顔で教えることはできないと思いますし、人々がそれを受け入れるとも思えません。int
auto
int
auto
for(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::index
ptrdiff_t
(index i = ... ; ... ; ...)
なぜ人々に書くように言わないのですか
ptrdiff_t
?なぜなら、C++ ではそうしなければならないと人々に伝えるのは恥ずかしいことであり、たとえ伝えたとしても、人々はそうしないだろうと私たちは考えているからです。とptrdiff_t
と比べると、書き方が醜すぎて採用できません。 名前を追加する目的は、正しいサイズの符号付き型をできるだけ簡単に、魅力的に使用できるようにすることです。auto
int
index
編集: ハーブ・サッターからのさらなる根拠
十分な大きさですか
ptrdiff_t
?ptrdiff_t
はい。2つの反復子を減算すると、difference_type に収まる必要があるため、標準のコンテナーでは、 で表すことができる数を超える要素を持つことがすでに要求されています。しかし、メモリ アドレス空間のサイズの半分よりも大きく、 で表現できるよりも多くの要素を持つまたは
ptrdiff_t
の組み込み配列がある場合、 は本当に十分な大きさでしょうか?char
byte
ptrdiff_t
はい。C++ では、配列の添え字に既に符号付き整数が使用されています。そのため、index
組み込み配列を含むほとんどの用途で、 をデフォルト オプションとして使用します。(アドレス空間の半分よりも大きく、要素が である配列または配列のような型という極めてまれなケースに遭遇し、sizeof(1)
切り捨ての問題を回避することに注意している場合は、size_t
その非常に特殊なコンテナーのみにインデックスを付けるために を使用してください。このような厄介なケースは実際には非常にまれであり、発生した場合でも、ユーザー コードによって直接インデックス付けされることはほとんどありません。たとえば、これらは通常、システムの割り当てを引き継いでユーザーが使用する個々の小さな割り当てを分割するメモリ マネージャー、または独自のインターフェイスを提供する MPEG または同様のもので発生します。どちらの場合も、 はsize_t
メモリ マネージャーまたは MPEG クラスの実装内で内部的にのみ必要になります。)