240

std::size_t代わりにforループなどを使用する必要があるのではないかと思っていますint。例えば:

#include <cstdint>

int main()
{
    for (std::size_t i = 0; i < 10; ++i) {
        // std::size_t OK here? Or should I use, say, unsigned int instead?
    }
}

一般的に、いつ使用するかに関するベストプラクティスは何std::size_tですか?

4

14 に答える 14

216

経験則として、ループ状態で自然にstd::size_tそれ自体であるものと比較する必要があるものはすべて使用できます。

std::size_tは任意の式のタイプでありsizeof、C ++で任意のオブジェクト(任意の配列を含む)の最大サイズを表現できることが保証されています。拡張により、任意の配列インデックスに対して十分な大きさであることが保証されているため、配列上のインデックスによるループの自然なタイプです。

数値を数えるだけの場合は、その数値を保持する変数のタイプ、intまたはunsigned int(十分に大きい場合は)または(十分に大きい場合)のいずれかを使用する方が自然な場合があります。これらはマシンの自然なサイズである必要があるためです。

于 2009-12-23T09:09:16.667 に答える
74

size_tsizeof演算子の結果タイプです。

size_t配列内のサイズまたはインデックスをモデル化する変数に使用します。size_tセマンティクスを伝達します。別の整数ではなく、バイト単位のサイズまたはインデックスを表すことがすぐにわかります。

また、size_tサイズをバイト単位で表すためにを使用すると、コードを移植可能にするのに役立ちます。

于 2009-12-23T09:09:31.763 に答える
37

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)。

于 2009-12-23T09:16:31.123 に答える
13

定義上、size_tsizeof演算子の結果です。size_tサイズを参照するために作成されました。

あなたが何かをする回数(あなたの例では10回)はサイズではないので、なぜ使用するのsize_tですか?int、またはunsigned int、は大丈夫です。

iもちろん、ループ内で何をするかも関係します。たとえば、をとる関数に渡す場合はunsigned int、を選択しunsigned intます。

いずれにせよ、暗黙の型変換は避けることをお勧めします。すべての型変換を明示的にします。

于 2009-12-23T09:06:50.713 に答える
13

短い答え:

ほとんどは決してない

長い答え:

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_tptrdiff_t、ではなくintです。ただしint、ほとんどの場合、size_tよりも使用する方がはるかに優れています。32ビットおよび64ビットシステム上にありますptrdiff_tlong

つまり、std :: containerを操作するときは常に、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) {
    [...]
}

ここにネイティブになるときのBjarneStroustrup(C ++作者)からのいくつかの言葉

一部の人々にとって、STLのこの符号付き/符号なしの設計エラーは、std :: vectorを使用せず、代わりに独自の実装を使用するのに十分な理由です。

于 2015-11-12T16:27:00.013 に答える
10

size_tsize_tは、アイテムのサイズディメンション(文字列の長さ、ポインタが取るバイト数など)を指定するための非常に読みやすい方法です。また、プラットフォーム間で移植可能です。64ビットと32ビットの両方がシステム関数で適切に動作することがわかります。うまくいかないかもしれない何かunsigned int(例えば、いつ使うべきか)unsigned long

于 2009-12-23T09:09:37.707 に答える
9

Cスタイルの配列のインデックス作成/カウントにはstd::size_tを使用します。

STLコンテナの場合、(たとえば)がvector<int>::size_typeあります。これは、ベクトル要素のインデックス作成とカウントに使用する必要があります。

実際には、これらは通常両方とも符号なしintですが、特にカスタムアロケータを使用する場合は保証されません。

于 2009-12-23T09:11:50.853 に答える
7

間もなく、ほとんどのコンピューターは64ビットアーキテクチャになり、64ビットOS:esは、数十億の要素のコンテナーで動作するプログラムを実行します。次に、ループインデックスとしてではなく、を使用する必要があります。そうしないと、32ビットシステムと64ビットシステムの両方で、インデックスが2 ^ 32:番目の要素でラップアラウンドします。size_tint

将来に備えましょう!

于 2011-04-27T10:46:47.110 に答える
5

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を使用することを好みます。

于 2016-07-20T17:27:59.337 に答える
4

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

他の人のコメントをお願いします。

于 2014-10-07T12:28:22.870 に答える
0

size_tは、アーキテクチャの最大整数値を保持できる符号なし型であるため、符号(signed int0x7FFFFFFFを1インクリメントすると-1になります)または短いサイズ(unsigned short int 0xFFFFを1にインクリメントすると)による整数オーバーフローから保護されます。 0)。

これは主に、配列のインデックス作成/ループ/アドレス演算などで使用されます。理論的には(32ビットプラットフォーム上で)サイズのメモリのブロックがある可能性があるため、同様の関数はmemset()受け入れるだけです。size_t2^32-1

このような単純なループの場合は、気にせず、intだけを使用してください。

于 2009-12-23T09:35:39.273 に答える
0

私はそれをいつ何を使うべきかを理解するのに苦労してきました。<stddef.h>, <stdio.h>, <stdlib.h>, <string.h>, <time.h>, <wchar.h>ただし、size_tは、などのさまざまなヘッダーファイルで定義されている符号なし整数データ型にすぎません 。

オブジェクトのサイズをバイト単位で表すために使用されるため、sizeof演算子によって戻り型として使用されます。最大許容サイズはコンパイラによって異なります。コンパイラが32ビットの場合、それはunsigned intのtypedef(エイリアス)ですが、コンパイラが64ビットの場合、unsignedlonglongのtypedefになります。size_tデータ型が負になることはありません(ssize_tを除く)。したがって、多くのCライブラリ関数はmalloc, memcpy and strlen、引数を宣言し、型をとして返しsize_tます。

/ Declaration of various standard library functions.
  
// Here argument of 'n' refers to maximum blocks that can be
// allocated which is guaranteed to be non-negative.
void *malloc(size_t n);
  
// While copying 'n' bytes from 's2' to 's1'
// n must be non-negative integer.
void *memcpy(void *s1, void const *s2, size_t n);
  
// the size of any string or `std::vector<char> st;` will always be at least 0.
size_t strlen(char const *s);

size_tまたは、ループ変数は通常0以上であるため、符号なしタイプはループ変数として使用されているように見える場合があります。

于 2022-01-01T11:23:26.413 に答える
-3

size_tは符号なし整数型であり、システムで最大の整数を表すことができます。非常に大きな配列、行列などが必要な場合にのみ使用してください。

一部の関数はsize_tを返し、比較を行おうとするとコンパイラが警告を発します。

適切な符号付き/符号なしデータ型を使用するか、単純に型キャストして高速ハックを行うことで、これを回避してください。

于 2009-12-23T09:41:42.280 に答える
-4

size_tはunsignedintです。したがって、unsigned intが必要な場合はいつでも、それを使用できます。

配列のサイズを指定したいときに使用します。

void * operator new (size_t size); is a good use of it.
于 2009-12-23T09:06:16.873 に答える