回答:
目安としては、ループ状態で自然に発生するものと比較する必要があるすべてのものを std::size_t
それ自体。
std::size_t
のタイプです sizeof
式、C ++で任意のオブジェクト(任意の配列を含む)の最大サイズを表現できることが保証されています。拡張により、配列のインデックスに対して十分な大きさであることが保証されているため、配列のインデックスによるループの自然な型です。
数まで数える場合は、その数を保持する変数のタイプ、int
またはunsigned int
(十分な大きさの場合)またはマシンの自然なサイズであるため、またはのいずれかを使用するほうが自然な場合があります。
ssize_t
符号付きの値もあります。
size_t
sizeof
演算子の結果タイプです。
size_t
配列のサイズまたはインデックスをモデル化する変数に使用します。size_t
セマンティクスを伝達します。これは、単に別の整数ではなく、バイト単位のサイズまたはインデックスを表すことがすぐにわかります。
また、size_t
サイズをバイト単位で表すのに使用すると、コードの移植性が高まります。
このsize_t
型は、文字列の長さを取得して各文字を処理するなど、使用するのが自然なように何かのサイズを指定するためのものです。
for (size_t i = 0, max = strlen (str); i < max; i++)
doSomethingWith (str[i]);
これは符号なしの型なので、もちろん境界条件に注意する必要があります。上端の境界は、最大値が通常大きいため(通常、そこに到達することは可能です)、それほど重要ではありません。ほとんどの人はint
、そのようなものに使用するだけです。それらの容量を超えるほど大きくなる構造体や配列はめったにないからですint
。
ただし、次のようなことに注意してください。
for (size_t i = strlen (str) - 1; i >= 0; i--)
これにより、符号なしの値のラッピング動作が原因で無限ループが発生します(ただし、コンパイラがこれに対して警告するのを見てきましたが)。これはまた、(理解するのが少し難しいが、少なくともラッピングの問題の影響を受けない)によって緩和することができます。
for (size_t i = strlen (str); i-- > 0; )
継続条件のチェック後の副作用にデクリメントをシフトすることにより、これはデクリメントの前に値の継続をチェックしますが、ループ内でデクリメントされた値を使用します(これは、ループがから実行される理由len .. 1
ですlen-1 .. 0
)。
strlen
ループの各繰り返しを呼び出すのは悪い習慣です。::)あなたはこのような何か行うことができますfor (size_t i = 0, len = strlen(str); i < len; i++) ...
for (size_t i = strlen (str); i --> 0;)
-->
"goes to"演算子(stackoverflow.com/questions/1642028/…を参照)の導入が好きかどうかはわかりませんが、それは実際にはかなり巧妙なトリックです。あなたの提案を答えに取り入れました。
if (i == 0) break;
forループの最後で簡単にできますか(例:for (size_t i = strlen(str) - 1; ; --i)
。(私はあなたのほうが好きですが、これでもうまくいくかどうか疑問に思います)
定義size_t
により、はsizeof
演算子の結果です。size_t
サイズを参照するために作成されました。
何かをする回数(例では10)はサイズに関するものではないので、なぜ使用するのsize_t
ですか?int
またはunsigned int
、大丈夫です。
もちろんi
、ループ内で何をするかにも関係があります。unsigned int
たとえばを受け取る関数に渡す場合は、を選択しunsigned int
ます。
いずれにせよ、暗黙的な型変換を避けることをお勧めします。すべての型変換を明示的にします。
ほとんどは決してない
32ビットシステムで2GBより大きいcharのベクトルが必要なときはいつでも。他のすべての使用例では、符号付きの型を使用する方が、符号なしの型を使用するよりもはるかに安全です。
例:
std::vector<A> data;
[...]
// calculate the index that should be used;
size_t i = calc_index(param1, param2);
// doing calculations close to the underflow of an integer is already dangerous
// do some bounds checking
if( i - 1 < 0 ) {
// always false, because 0-1 on unsigned creates an underflow
return LEFT_BORDER;
} else if( i >= data.size() - 1 ) {
// if i already had an underflow, this becomes true
return RIGHT_BORDER;
}
// now you have a bug that is very hard to track, because you never
// get an exception or anything anymore, to detect that you actually
// return the false border case.
return calc_something(data[i-1], data[i], data[i+1]);
の符号付き同等物size_t
はptrdiff_t
、ではなくint
です。しかしint
、ほとんどの場合、size_tよりも使用する方がはるかに優れています。ptrdiff_t
ですlong
32ビットおよび64ビットシステムで。
これは、std :: containersを操作するときは常にsize_tとの間で変換を行う必要があることを意味します。しかし、進行中のネイティブ会議で、c ++の作成者は、署名されていないsize_tを使用してstd :: vectorを設計するのは誤りであると述べました。
コンパイラーがptrdiff_tからsize_tへの暗黙の変換について警告を出す場合、コンストラクター構文で明示的にすることができます。
calc_something(data[size_t(i-1)], data[size_t(i)], data[size_t(i+1)]);
境界チェックなしで、単にコレクションを反復処理したい場合は、以下に基づいて範囲を使用します。
for(const auto& d : data) {
[...]
}
ここで、ネイティブに移行する際のBjarne Stroustrup(C ++作成者)からのいくつかの単語
一部の人々にとって、STD :: vectorを使用せずに、独自の実装を使用するには、STLでのこの署名付き/署名なしの設計エラーが十分な理由です。
for(int i = 0; i < get_size_of_stuff(); i++)
。さて、確かに、あなたは生のループをたくさんしたくないかもしれませんが-さあ、あなたもそれらを使います。
x + 1 < y
同等ですがx < y - 1
、非固有整数ではありません。同等であると想定されているものが変換されるときに、バグが簡単に発生する可能性があります。
Cスタイルの配列のインデックス付け/カウントにはstd :: size_tを使用します。
STLコンテナーの場合は(たとえば)がありvector<int>::size_type
、これはベクター要素のインデックス作成とカウントに使用する必要があります。
実際には、通常両方ともunsigned intですが、特にカスタムアロケーターを使用する場合は保証されません。
std::size_t
通常(4バイト)unsigned long
ではなくunisgned int
(64ビットシステムでは8 バイト)。
size_t
、インデックスが負になる可能性があるため、インデックスが付けられません。size_t
ただし、負になりたくない場合は、このような配列の独自のインスタンスを使用できます。
+
、ポインターに演算子を使用することと同等であるptrdiff_t
ため、インデックスに使用するのはそれだと思われます。
vector<T>::size_type
(他のすべてのコンテナの同上)、効果的であることが保証されているため、実際にはかなり無用だsize_t
-それがにtypedefされますAllocator::size_type
特に、 - 、およびコンテナに関して、その上の制限については、20.1.5 / 4参照size_type
必見ことsize_t
、およびdifference_type
なければなりませんptrdiff_t
。もちろん、デフォルトstd::allocator<T>
はこれらの要件を満たしています。ですから、短い方size_t
を使用し、残りの部分は気にしないでください:)
間もなく、ほとんどのコンピュータは64ビットOSの64ビットアーキテクチャになり、何十億もの要素のコンテナで動作するプログラムを実行します。次に、ループインデックスの代わりに使用する必要があります。そうしないと、32ビットシステムと64ビットシステムの両方で、インデックスが2 ^ 32:番目の要素で折り返されます。size_t
int
未来に備えよう!
long int
でなくが必要であるという意味でのみ有効int
です。場合はsize_t
、64ビットOSに関連しているそれは、32ビットOS上で同じように関連しました。
size_tを使用する場合は、次の式に注意してください。
size_t i = containner.find("mytoken");
size_t x = 99;
if (i-x>-1 && i+x < containner.size()) {
cout << containner[i-x] << " " << containner[i+x] << endl;
}
xの値に関係なく、if式ではfalseになります。これを実現するのに数日かかりました(コードは非常にシンプルなので、単体テストを実行しませんでした)が、問題の原因を特定するには数分しかかかりません。キャストするか、ゼロを使用する方が良いかわかりません。
if ((int)(i-x) > -1 or (i-x) >= 0)
どちらの方法でも機能するはずです。これが私のテストランです
size_t i = 5;
cerr << "i-7=" << i-7 << " (int)(i-7)=" << (int)(i-7) << endl;
出力:i-7 = 18446744073709551614(int)(i-7)=-2
他人のコメントをお願いします。
(int)(i - 7)
は、int
後にキャストさint(i) - 7
れるアンダーフローですが、最初にに変換してi
からint
減算するため、アンダーフローではないことに注意してください7
。さらに、私はあなたの例を混乱させました。
size_tはさまざまなライブラリーから返され、そのコンテナーのサイズがゼロ以外であることを示します。あなたが一度戻ってきたときにあなたはそれを使います:0
ただし、上記の例では、size_tでのループは潜在的なバグです。以下を検討してください。
for (size_t i = thing.size(); i >= 0; --i) {
// this will never terminate because size_t is a typedef for
// unsigned int which can not be negative by definition
// therefore i will always be >= 0
printf("the never ending story. la la la la");
}
符号なし整数を使用すると、これらのタイプの微妙な問題が発生する可能性があります。したがって、私は私がそれを必要とするコンテナ/タイプと対話するときだけ私がsize_tを使うことを好む。
size_t
は、ご使用のアーキテクチャーの最大整数値を保持できる符号なしタイプであるため、符号(signed int)による整数オーバーフローから保護されています 0x7FFFFFFF
を1ずつインクリメントすると-1が返されます)または短いサイズ(unsigned short int 0xFFFFを1ずつインクリメントするとます) 0)。
主に配列のインデックス付け/ループ/アドレス演算などに使用されます。のような関数は、理論的にはサイズのメモリブロックがあるため、memset()
受け入れるsize_t
だけです。2^32-1
(32ビットプラットフォーム)。
そのような単純なループの場合、気にせず、intだけを使用します。
size_tは、システムで最大の整数を表すことができる符号なし整数型です。非常に大きな配列、行列などが必要な場合にのみ使用してください。
一部の関数はsize_tを返し、比較を行おうとするとコンパイラーから警告が出されます。
適切な署名済み/未署名のデータ型を使用するか、高速ハックのために単純に型キャストすることで、これを回避します。
size_tは符号なし整数です。そのため、unsigned intが必要なときはいつでも使用できます。
配列のサイズを指定したいときに使用します...
void * operator new (size_t size); is a good use of it.
size_t
は、符号なし64ビット整数になる可能性がありますが、32ビットマシンでは、32ビットの符号なし整数のみになります。
size_t
ます。