size_tが何bitになるかは環境によって定義が異なります。
そのため、以下のコードは多くの32bit下で上手くいきますが、64bit化などで環境が変わると動かなくなります。

#include <string>

int main () {
  std::string test = "test text";
  unsigned int pos = 0;

  printf("size_t %lu\n", sizeof(size_t));

  pos = test.find("ms");
  printf("pos %lu, %lu\n", (size_t)pos, std::string::npos);
  if(pos != std::string::npos){
    std::string text = test.substr(pos);
    printf("%s\n", text.c_str());
  }

  return 0;
}

std::stringのfindは引数の文字列が最初に出てくる位置か、見つからなかった場合にstd::string::nposを返します。
この時、戻り値の型はsize_tになります。

size_tは32bit上ではunsigned intの別名として定義される事が多いため、上記のコードは問題なく動きます。
ですが64bitにした場合、size_tはunsigned long(8bit)の別名として定義される事があるため、
unsigned int(4bit)で表せない範囲の値だった場合はデータが一部消滅します。

さらに、std::string::nposは-1として定義されており、unsignedとして解釈した場合にはその値の最大値になります。
size_tがunsigned intの場合、両者は同じ大きさのため特に意識する必要はありません。

ですが、size_tがunsigned longとして定義されている場合、その最大値はunsined intでは表せないため、
データが消滅し、結果として比較に失敗するという事が起きます。

私の環境では、上記のコードは-1をunsigend intにした4294967295と,
-1をunsigend longにした18446744073709551615とを比較し、
test textの4294967295文字目にアクセスして異常終了します。

やっかいなことに、size_tをunsigned intではなくintに代入した場合、
-1は-1として解釈されるため、unsigend longと比較した際に最大値に変換されるため、上手くいってしまいます。

とはいえ、安全性を求めるならば、出来るだけsize_tはsize_tとして扱うようにした方がいいと思います。

このエントリーをはてなブックマークに追加