web-dev-qa-db-ja.com

「符号付き/符号なしの不一致」警告(C4018)に対処するにはどうすればよいですか?

私は、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は現在のインデックスを必要とします。また、入力する必要があるすべての追加コード(イテレータ自体とインデックス)は、問題を複雑にし、基礎となるコードの単純さをわかりにくくします。

71
Andrew T

すべて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) { /**/ }
52
udpn

理想的には、代わりに次のような構造を使用します。

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

これにより、コンパイラに対する意図が明確に指定されます。警告が表示されてもバグは発生しません。

13
ereOn

イテレータを使用できない/使用できない場合、およびループインデックスに_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)問題の両方が解決されることに注意してください。すべての警告を有効のままにしておき、それらを使用してコードの他の部分の実際のバグをキャッチできます。

7
Adrian McCarthy

次を使用できます。

  1. size_tタイプ、警告メッセージを削除する
  2. イテレータ+距離(最初のヒントのように)
  3. イテレータのみ
  4. 関数オブジェクト

例えば:

// 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());
}
6
siquell

より良いアイデアをお伝えします

_for(decltype(things.size()) i = 0; i < things.size(); i++){
                   //...
}
_

decltype

エンティティの宣言されたタイプ、または式のタイプと値のカテゴリを検査します。

したがって、things.size()の型を推定し、ithings.size()と同じ型になります。したがって、i < things.size()は警告なしで実行されます

3
Daniel

C++ 11の次のソリューションも提案できます。

for (auto p = 0U; p < sys.size(); p++) {

}

(C++は自動p = 0に対して十分にスマートではないため、p = 0Uを配置する必要があります。..)

3

同様の問題がありました。 size_tを使用しても機能しませんでした。私のために働いた他のものを試しました。 (以下のように)

for(int i = things.size()-1;i>=0;i--)
{
 //...
}
1
Karthik_elan

ただやる

int pnSize = primeNumber.size();
for (int i = 0; i < pnSize; i++)
    cout << primeNumber[i] << ' ';
0
Don Larynx