Pergunta

O que é a maneira correta de iteração sobre um vetor em C ++?

Considere estes dois fragmentos de código, este funciona muito bem:

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

e este:

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

que gera warning: comparison between signed and unsigned integer expressions.

Eu sou novo no mundo do C ++, então a variável unsigned parece um pouco assustador para mim e eu sei variáveis ??unsigned pode ser perigoso se não for usado corretamente, de modo - isto é correto

?
Foi útil?

Solução

Iterating Backwards

Consulte esta resposta .

Iterating Forwards

Isto é quase idêntico. Basta alterar o decréscimo iterators / swap pelo incremento. Você deve preferir iteradores. Algumas pessoas dizem para você usar std::size_t como o tipo de índice variável. No entanto, isso não é portátil. Sempre use o typedef size_type do recipiente (Enquanto você poderia começar afastado com apenas uma conversão no caso iteração para a frente, ele poderia realmente dar errado todo o caminho no caso iteração para trás ao usar std::size_t, no caso std::size_t é mais amplo do que o que é o typedef de size_type):

Usando std :: vector

Usando iteradores

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

importante é, sempre use o formulário incremento de prefixo para iterators cujas definições você não sabe. Isso irá garantir que seus código é executado o mais genérico possível.

Usando Faixa C ++ 11

for(auto const& value: a) {
     /* std::cout << value; ... */

Usando índices

for(std::vector<int>::size_type i = 0; i != v.size(); i++) {
    /* std::cout << v[i]; ... */
}

usando matrizes

Usando iteradores

for(element_type* it = a; it != (a + (sizeof a / sizeof *a)); it++) {
    /* std::cout << *it; ... */
}

Usando Faixa C ++ 11

for(auto const& value: a) {
     /* std::cout << value; ... */

Usando índices

for(std::size_t i = 0; i != (sizeof a / sizeof *a); i++) {
    /* std::cout << a[i]; ... */
}

Leia na resposta a iteração para trás o problema da abordagem sizeof pode ceder, apesar de tudo.

Outras dicas

Quatro anos se passaram, Google me deu esta resposta. Com o C ++ 11 (aka C ++ 0x ) há realmente uma nova maneira agradável de fazer isso (ao preço de quebrar compatibilidade com versões anteriores): a nova palavra-chave auto. Isso evita que você a dor de ter que especificar explicitamente o tipo de iterador para uso (repetindo o tipo de vector de novo), quando é óbvio (para o compilador), que tipo de uso. Com v ser seu vector, você pode fazer algo como isto:

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

C ++ 11 vai ainda mais longe e dá-lhe uma sintaxe especial para a iteração sobre coleções como vetores. Ele remove a necessidade de escrever coisas que são sempre os mesmos:

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

Para vê-lo em um programa de trabalho, construir uma auto.cpp arquivo:

#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;
}

Como de escrever este, quando você compilar este com g ++ , você normalmente precisará configurá-lo para trabalhar com o novo padrão, dando uma bandeira Extra:

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

Agora você pode executar o exemplo:

$ ./auto
17
12
23
42

Por favor nota que as instruções sobre a compilação e execução são específicos para GNU C ++ compilador em Linux , o programa deve ser plataforma (e compilador ) independente.

No caso específico no seu exemplo, eu uso os algoritmos STL para alcançar este objetivo.

#include <numeric> 

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

Para um caso mais geral, mas ainda bastante simples, eu iria com:

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

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

Com relação a resposta de Johannes Schaub:

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

Esse trabalho pode com alguns compiladores, mas não com gcc. O problema aqui é a questão se std :: vector :: iteração é um tipo, um variável (membro) ou uma função (método). Ficamos com o seguinte erro com 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

A solução é usar a palavra-chave 'typename' como disse:

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

Uma chamada para vector<T>::size() retorna um valor do tipo std::vector<T>::size_type, não int, int não assinado ou de outra forma.

Também geralmente iteração sobre um recipiente em C ++ é feito usando iterators , como este.

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

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

Onde T é o tipo de dados que armazenam no vetor.

Ou usando os diferentes algoritmos de iteração (std::transform, std::copy, std::fill, std::for_each et cetera).

Use size_t:

for (size_t i=0; i < polygon.size(); i++)

Wikipedia :

Os arquivos de cabeçalho stdlib.h e stddef.h definir um tipo de dados chamado size_t que é usado para representar o tamanho de um objeto. funções de biblioteca que levam tamanhos esperar que eles sejam do tipo size_t, e os avalia operador sizeof para size_t.

O tipo real de size_t é dependente de plataforma; um erro comum é assumir size_t é o mesmo que int não assinado, que pode levar a erros de programação, particularmente como arquiteturas de 64 bits se tornam mais prevalentes.

Eu costumo usar BOOST_FOREACH:

#include <boost/foreach.hpp>

BOOST_FOREACH( vector_type::value_type& value, v ) {
    // do something with 'value'
}

Ele funciona em recipientes STL, matrizes, cordas de estilo C, etc.

Um pouco de história:

Para representar se um número é uso negativo ou não computador um 'sinal' bit. int é um tipo de dados assinado o que significa que pode conter valores positivos e negativos (cerca -2billion a 2 bilhões). Unsigned só pode armazenar números positivos (e uma vez que não perca um pouco de metadados que pode armazenar mais: 0 a cerca de 4 bilhões).

std::vector::size() retorna um unsigned, pois como poderia um vetor tem comprimento negativo?

O aviso está lhe dizendo que o operando direito da sua declaração desigualdade pode armazenar mais dados, em seguida, à esquerda.

Essencialmente, se você tem um vetor com mais de 2 bilhões de entradas e você usar um inteiro para o índice em que você vai bater estouro problemas (o int vai embrulhar ao redor para negativa 2 bilhões).

Para ser completa, C ++ 11 sintaxe permite apenas uma outra versão para iterators ( ref ):

for(auto it=std::begin(polygon); it!=std::end(polygon); ++it) {
  // do something with *it
}

O que também é confortável para iteração inversa

for(auto it=std::end(polygon)-1; it!=std::begin(polygon)-1; --it) {
  // do something with *it
}

Em C ++ 11

Gostaria de usar algoritmos gerais como for_each a busca evitar para o tipo certo de iterador e expressão lambda para evitar funções extras chamados / objetos.

O curta "bonito" exemplo para o seu caso particular (assumindo polígono é um vetor de inteiros):

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

testado em: http://ideone.com/i6Ethd

'Não se esqueça de incluem: algoritmo e, é claro, vetor:)

A Microsoft tem, na verdade também um bom exemplo sobre isso:
Fonte: 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;
}
for (vector<int>::iterator it = polygon.begin(); it != polygon.end(); it++)
    sum += *it; 

A primeira é do tipo correto e correto em algum sentido estrito. (Se você pensar é, o tamanho nunca pode ser inferior a zero.) Essa advertência parece-me como um dos bons candidatos para ser ignorado, apesar de tudo.

Considere se você precisa iterate em tudo

O cabeçalho padrão <algorithm> nos fornece instalações para isso:

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

Outras funções na biblioteca algoritmo de executar tarefas comuns - verifique se você sabe o que está disponível se você quiser salvar a si mesmo esforço

.

Obscure, mas importante detalhe: se você disser "para (auto-lo)" como se segue, você tem uma cópia do objeto, e não o elemento real:

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]

Para modificar os elementos do vetor, você precisa definir o iterador como referência:

for(auto &it : v)

Se suas sustentações do compilador-lo, você poderia usar um intervalo com base para acessar os elementos do vetor:

vector<float> vertices{ 1.0, 2.0, 3.0 };

for(float vertex: vertices){
    std::cout << vertex << " ";
}

Prints: 1 2 3. Note, você não pode usar esta técnica para alterar os elementos do vetor.

Os dois segmentos de código funcionam da mesma forma. No entanto, sem assinatura int" rota está correta. Usando tipos int sem sinal vai funcionar melhor com o vector na instância que você usou. Chamar a função membro size () em um vetor retorna um valor inteiro sem sinal, assim que você quer ser comparando a variável "i" para um valor de seu próprio tipo.

Além disso, se você ainda está um pouco inquieto sobre como parece "unsigned int" em seu código, tente "uint". Esta é basicamente uma versão abreviada de "int não assinado" e ele funciona exatamente da mesma. Você também não precisa incluir outros cabeçalhos de usá-lo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top