表題は、私が最近見かけた、C++プログラマーならば見た瞬間に「まずいかも」と思うであろう式。
(※containerは実際には別の名前)
表題の式が問題になる例
#include <iostream>
#include <vector>
void compare(int n, const std::vector<int>& container)
{
std::cout << n << " - 1";
if (n - 1 >= container.size())
{
std::cout << " >= ";
}
else
{
std::cout << " < ";
}
std::cout << container.size() << std::endl;
}
int main()
{
std::vector<int> v(2);
compare(3, v);
compare(2, v);
compare(1, v);
compare(0, v);
return 0;
}
結果
3 - 1 >= 2
2 - 1 < 2
1 - 1 < 2
0 - 1 >= 2
表題の式を見た瞬間に「まずいかも」と思う理屈
- containerはC++のコンテナではなかろうかと推論できる
- C++のコンテナは要素数の表現にsize_t型を用いることが多い
- size_t型は、最高級の整数変換順位を持っている符号なしの型(unsigned long)であることが多い
- そのため、int型の値とsize_t型の値の比較は、int型の値をsize_t型に変換して(正数に丸めて)から行われる
- たとえば (int)-1 < (size_t)2 は(32ビットの処理系では) (size_t)4294967295 < (size_t)2 となる
以上を踏まえ、そもそも
if (n > container.size())
で問題なさそうなところをわざわざこのように書かれる妥当な理由が思い付かないため、コード品質の面に不安を覚える。
size_t型についての所感
C99ではsize_t型について“signed longより高い整数変換順位を持つべきではない。ただし、処理系がこのことを必要とするほど、大きなオブジェクトをサポートしている場合を除く”とされている。
もともとsize_t型は「sizeof演算子の結果を表現する型」であり、私自身は「sizeof演算子の結果として(ついでに言うとC++コンテナの要素数としても)signed longよりも大きな値が必要となるソフトウェア」に携わったことがないこともあり、多くの処理系のsize_tは元々の要件に対して安全性の低い選択肢が採られているように感じる。