配列 - c++ イテレータ




反復のstd:: vector:符号なしインデックス変数 (11)

C ++でベクトルを反復処理する正しい方法は何ですか?

これらの2つのコードの断片を考えてみましょう。これはうまくいきます:

for (unsigned i=0; i < polygon.size(); i++) {
    sum += polygon[i];
}

この1つ:

for (int i=0; i < polygon.size(); i++) {
    sum += polygon[i];
}

warning: comparison between signed and unsigned integer expressionsを生成しwarning: comparison between signed and unsigned integer expressions

私はC ++の世界では新しく、 unsigned変数は私にとっては恐ろしいものに見えますが、 unsignedれていunsigned変数は正しく使用されないと危険です。


C ++ 11では

私はfor_eachような一般的なアルゴリズムを使用して、イテレータとラムダ式の適切な型を検索し、余分な名前の関数/オブジェクトを避けます。

あなたの特定のケースの短い "かなり"の例(多角形が整数のベクトルであると仮定します):

for_each(polygon.begin(), polygon.end(), [&sum](int i){ sum += i; });

テスト済み: http://ideone.com/i6Ethd : http://ideone.com/i6Ethd

含まないことを忘れてくださいアルゴリズムと、もちろん、ベクトル:)

マイクロソフトでは実際にこれについての良い例もあります。
ソース: http://msdn.microsoft.com/en-us/library/dd293608.aspx : http://msdn.microsoft.com/en-us/library/dd293608.aspx

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int main() 
{
   // Create a vector object that contains 10 elements.
   vector<int> v;
   for (int i = 1; i < 10; ++i) {
      v.push_back(i);
   }

   // Count the number of even numbers in the vector by 
   // using the for_each function and a lambda.
   int evenCount = 0;
   for_each(v.begin(), v.end(), [&evenCount] (int n) {
      cout << n;
      if (n % 2 == 0) {
         cout << " is even " << endl;
         ++evenCount;
      } else {
         cout << " is odd " << endl;
      }
   });

   // Print the count of even numbers to the console.
   cout << "There are " << evenCount 
        << " even numbers in the vector." << endl;
}

あなたがすべてを反復する必要があるかどうかを検討する

<algorithm>標準ヘッダは、このための機能を私たちに提供します:

using std::begin;  // allows argument-dependent lookup even
using std::end;    // if the container type is unknown here
auto sum = std::accumulate(begin(polygon), end(polygon), 0);

アルゴリズムライブラリの他の関数は一般的なタスクを実行します。自分の労力を節約したい場合には、利用可能なものを確認してください。


2つのコードセグメントは同じ働きをします。 しかし、unsigned int型のルートは正しいです。unsigned int型を使用すると、それを使ったインスタンスのベクトルがうまく動作します。ベクトル上のsize()メンバ関数を呼び出すと、符号なし整数値が返されます。 "i"はそれ自身の型の値になります。

また、あなたのコードで "unsigned int"がどのように見えるか不安なら、 "uint"を試してみてください。 これは基本的に "unsigned int"の短縮バージョンであり、まったく同じように動作します。 また、他のヘッダーを使用する必要はありません。


4年が過ぎて、 Googleは私にこの答えをくれました。 標準的なC ++ 11 (別名C ++ 0xでは 、実際にこれを行ううれしい新しい方法があります(下位互換性を壊すという価格で):新しいautoキーワード。 使用するイテレーターのタイプを明示的に指定すること(ベクトルタイプをやり直す)、明示的に(コンパイラーに)、使用するタイプを明示的に指定しなければならないという苦労がなくなります。 vがあなたのvectorである場合、次のようなことができます:

for ( auto i = v.begin(); i != v.end(); i++ ) {
    std::cout << *i << std::endl;
}

C ++ 11はさらに進んでおり、ベクトルのようなコレクションを繰り返し処理するための特殊な構文を提供します。 常に同じものを書く必要がなくなります。

for ( auto &i : v ) {
    std::cout << i << std::endl;
}

作業中のプログラムでそれを見るには、 auto.cppファイルをauto.cppます:

#include <vector>
#include <iostream>

int main(void) {
    std::vector<int> v = std::vector<int>();
    v.push_back(17);
    v.push_back(12);
    v.push_back(23);
    v.push_back(42);
    for ( auto &i : v ) {
        std::cout << i << std::endl;
    }
    return 0;
}

これを書いている時点で、 g ++でこれをコンパイルするときには、追加のフラグを付けることによって、通常は新しい標準で動作するように設定する必要があります:

g++ -std=c++0x -o auto auto.cpp

これで例を実行できます:

$ ./auto
17
12
23
42

コンパイルと実行の手順はLinuxの GNU C ++コンパイラに固有のものであり、プログラムはプラットフォーム(およびコンパイラ)に依存しないものであることに注意してください


vector<T>::size() std::vector<T>::size_typeはint型、unsigned int型ではなくstd::vector<T>::size_type型の値を返します。

また、一般的に、C ++のコンテナに対する反復は、 イテレータを使用して行われます

std::vector<T>::iterator i = polygon.begin();
std::vector<T>::iterator end = polygon.end();

for(; i != end; i++){
    sum += *i;
}

ここで、Tはベクトルに格納するデータのタイプです。

または異なる反復アルゴリズム( std::transformstd::copystd::fillstd::for_eachなど)を使用します。


あなたの例の特定の場合、私はこれを達成するためにSTLアルゴリズムを使用します。

#include <numeric> 

sum = std::accumulate( polygon.begin(), polygon.end(), 0 );

より一般的な、しかしまだかなり単純な場合、私は一緒に行くだろう:

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

using namespace boost::lambda;
std::for_each( polygon.begin(), polygon.end(), sum += _1 );

ヨハネス・シャウブの答えについて:

for(std::vector<T*>::iterator it = v.begin(); it != v.end(); ++it) { 
...
}

これはコンパイラによっては動作しますがgccでは動作しません。 ここで問題となるのは、std :: vector :: iteratorが型、変数(メンバ)または関数(メソッド)の場合です。 gccで次のエラーが発生します。

In member function ‘void MyClass<T>::myMethod()’:
error: expected `;' before ‘it’
error: ‘it’ was not declared in this scope
In member function ‘void MyClass<T>::sort() [with T = MyClass]’:
instantiated from ‘void MyClass<T>::run() [with T = MyClass]’
instantiated from here
dependent-name ‘std::vector<T*,std::allocator<T*> >::iterator’ is parsed as a non-type, but instantiation yields a type
note: say ‘typename std::vector<T*,std::allocator<T*> >::iterator’ if a type is meant

解決策は、キーワード 'typename'を以下のように使用しています。

typename std::vector<T*>::iterator it = v.begin();
for( ; it != v.end(); ++it) {
...

不明瞭だが重要な詳細:次のように "for(auto it)"と言うと、実際の要素ではなくオブジェクトのコピーが得られる。

struct Xs{int i} x;
x.i = 0;
vector <Xs> v;
v.push_back(x);
for(auto it : v)
    it.i = 1;         // doesn't change the element v[0]

ベクトルの要素を変更するには、イテレータを参照として定義する必要があります。

for(auto &it : v)

少しの歴史:

数字が否定的であるか否かを表すために、コンピュータは「符号」ビットを使用する。 intは符号付きのデータ型で、正と負の値(約20〜20億)を保持できることを意味します。 Unsignedは正の数しか格納できません(メタデータに少しでも浪費することはありませんので、0〜約4億のデータを格納できます)。

std::vector::size()は、ベクトルが負の長さを持つ方法について、 unsigned返します。

警告は、不等式ステートメントの右オペランドに、より多くのデータを保持できることを伝えています。

本質的には、20億以上のエントリを持つベクトルがあり、インデックスに整数を使用するとオーバーフローの問題が発生します(intは20億の負の値に戻ります)。


最初の型は正しい型であり、厳密には正しい型です。 (もしあなたがそうであると思うなら、サイズは決してゼロより小さくなることはありません)。その警告は無視される良い候補の1つとして私を襲う。


for (vector<int>::iterator it = polygon.begin(); it != polygon.end(); it++)
    sum += *it; 




signed