私は、C++で記述された多くの計算コードを、高いパフォーマンスと低いメモリオーバーヘッドを考慮して使用しています。 STLコンテナー(主にvector
)を多く使用し、ほぼすべての単一機能でそのコンテナーを反復処理します。
反復コードは次のようになります。
for (int i = 0; i < things.size(); ++i)
{
// ...
}
しかし、signed/unsigned mismatch警告(Visual StudioのC4018)を生成します。
int
をいくつかのunsigned
型に置き換えることは、OpenMPプラグマを頻繁に使用するため問題であり、カウンターはint
である必要があります。
(数百の)警告を抑制しようとしていますが、この問題に対するエレガントな解決策を見逃しているのではないかと心配しています。
イテレータ上。イテレータは適切な場所に適用すると素晴らしいと思います。私が使用しているコードは、neverランダムアクセスコンテナをlist
または何かに変更します(したがって、int i
はすでにコンテナに依存しない)、alwaysは現在のインデックスを必要とします。また、入力する必要があるすべての追加コード(イテレータ自体とインデックス)は、問題を複雑にし、基礎となるコードの単純さをわかりにくくします。
すべてthings.size()
タイプにあります。 int
ではなく、size_t
(CではなくC++に存在する)これは、「通常の」符号なし型、つまりunsigned int
x86_32の場合.
演算子 "less"(<)は、異なる符号の2つのオペランドに適用できません。コンパイラーが暗黙的な符号変換を行うことができるかどうかは、そのようなオペコードはなく、標準では指定されていません。そのため、符号付きの数値を符号なしとして扱い、その警告を発します。
次のように書くのが正しいでしょう
for (size_t i = 0; i < things.size(); ++i) { /**/ }
またはさらに高速
for (size_t i = 0, ilen = things.size(); i < ilen; ++i) { /**/ }
理想的には、代わりに次のような構造を使用します。
for (std::vector<your_type>::const_iterator i = things.begin(); i != things.end(); ++i)
{
// if you ever need the distance, you may call std::distance
// it won't cause any overhead because the compiler will likely optimize the call
size_t distance = std::distance(things.begin(), i);
}
これには、コードが突然コンテナに依存しないというすばらしい利点があります。
あなたの問題に関して、使用するライブラリがint
を使用する必要がある場合、unsigned int
はより適切で、APIは乱雑です。とにかく、それらのint
が常に正であることを確信しているなら、あなたはただすることができます:
int int_distance = static_cast<int>(distance);
これにより、コンパイラに対する意図が明確に指定されます。警告が表示されてもバグは発生しません。
イテレータを使用できない/使用できない場合、およびループインデックスに_std::size_t
_を使用できない/使用できない場合は、.size()
からint
への変換関数を作成します。仮定を文書化し、コンパイラの警告を黙らせるために明示的に変換を行います。
_#include <cassert>
#include <cstddef>
#include <limits>
// When using int loop indexes, use size_as_int(container) instead of
// container.size() in order to document the inherent assumption that the size
// of the container can be represented by an int.
template <typename ContainerType>
/* constexpr */ int size_as_int(const ContainerType &c) {
const auto size = c.size(); // if no auto, use `typename ContainerType::size_type`
assert(size <= static_cast<std::size_t>(std::numeric_limits<int>::max()));
return static_cast<int>(size);
}
_
次に、ループを次のように記述します。
_for (int i = 0; i < size_as_int(things); ++i) { ... }
_
この関数テンプレートのインスタンス化はほぼ確実にインライン化されます。デバッグビルドでは、仮定がチェックされます。リリースビルドでは、そうではなく、size()を直接呼び出したかのようにコードが高速になります。どちらのバージョンでもコンパイラの警告は生成されず、慣用的なループのわずかな変更にすぎません。
リリースバージョンでも同様に仮定の失敗をキャッチしたい場合は、アサーションをstd::out_of_range("container size exceeds range of int")
のような何かをスローするifステートメントに置き換えることができます。
これにより、符号付き/符号なし比較と潜在的なsizeof(int)
!= sizeof(Container::size_type)
問題の両方が解決されることに注意してください。すべての警告を有効のままにしておき、それらを使用してコードの他の部分の実際のバグをキャッチできます。
次を使用できます。
例えば:
// simple class who output his value
class ConsoleOutput
{
public:
ConsoleOutput(int value):m_value(value) { }
int Value() const { return m_value; }
private:
int m_value;
};
// functional object
class Predicat
{
public:
void operator()(ConsoleOutput const& item)
{
std::cout << item.Value() << std::endl;
}
};
void main()
{
// fill list
std::vector<ConsoleOutput> list;
list.Push_back(ConsoleOutput(1));
list.Push_back(ConsoleOutput(8));
// 1) using size_t
for (size_t i = 0; i < list.size(); ++i)
{
std::cout << list.at(i).Value() << std::endl;
}
// 2) iterators + distance, for std::distance only non const iterators
std::vector<ConsoleOutput>::iterator itDistance = list.begin(), endDistance = list.end();
for ( ; itDistance != endDistance; ++itDistance)
{
// int or size_t
int const position = static_cast<int>(std::distance(list.begin(), itDistance));
std::cout << list.at(position).Value() << std::endl;
}
// 3) iterators
std::vector<ConsoleOutput>::const_iterator it = list.begin(), end = list.end();
for ( ; it != end; ++it)
{
std::cout << (*it).Value() << std::endl;
}
// 4) functional objects
std::for_each(list.begin(), list.end(), Predicat());
}
より良いアイデアをお伝えします
_for(decltype(things.size()) i = 0; i < things.size(); i++){
//...
}
_
decltype
は
エンティティの宣言されたタイプ、または式のタイプと値のカテゴリを検査します。
したがって、things.size()
の型を推定し、i
はthings.size()
と同じ型になります。したがって、i < things.size()
は警告なしで実行されます
C++ 11の次のソリューションも提案できます。
for (auto p = 0U; p < sys.size(); p++) {
}
(C++は自動p = 0に対して十分にスマートではないため、p = 0Uを配置する必要があります。..)
同様の問題がありました。 size_tを使用しても機能しませんでした。私のために働いた他のものを試しました。 (以下のように)
for(int i = things.size()-1;i>=0;i--)
{
//...
}
ただやる
int pnSize = primeNumber.size();
for (int i = 0; i < pnSize; i++)
cout << primeNumber[i] << ' ';