Pergunta

Qual das seguintes é melhor e por quê? (Particular para c ++)

a.

int i(0), iMax(vec.length());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
  //loop body
}

b.

for( int i(0);i < vec.length(); ++i)
{
  //loop body
}

Eu vi conselho para (a) por causa da chamada para a função comprimento. Isso está me incomodando. Não qualquer compilador moderna que a otimização de (b) ser semelhante ao (a)?

Foi útil?

Solução

Exemplo (b) tem um significado diferente ao exemplo (a), e o compilador deve interpretá-lo como você escrevê-lo.

Se, (por alguma razão fez-up que eu não posso pensar), eu escrevi código para fazer isso:

for( int i(0);i < vec.length(); ++i)
{
    if(i%4 == 0)
       vec.push_back(Widget());
}

Eu realmente não teria queria o compilador para otimizar a cada chamada para vec.length (), porque eu obter resultados diferentes.

Outras dicas

Eu como:

for (int i = 0, e = vec.length(); i != e; ++i)

É claro, isso também trabalho para iterators:

for (vector<int>::const_iterator i = v.begin(), e = v.end(); i != e; ++i)

Eu gosto deste porque é ao mesmo tempo eficiente (end() chamar apenas uma vez), e também relativamente sucinta (somente ter que digitar vector<int>::const_iterator uma vez).

Estou surpreso ninguém disse o óbvio:

Em 99,99% dos casos, não importa.

A menos que você estiver usando algum recipiente onde cálculo size() é uma operação cara, é incompreensível que o seu programa vai ainda alguns nanossegundos mais lento. Eu diria que ficar com o mais legível até o perfil de seu código e achar que size() é um gargalo.

Há duas questões a debater aqui:

  1. O escopo de variáveis ??
  2. A condição final re-avaliação

O escopo de variáveis ??

Normalmente, você não precisa a variável loop para ser visível fora do loop. É por isso que você pode declará-lo dentro da construção for.

condição End re-avaliação

Andrew Shepherd afirmou-lo bem: isso significa algo diferente para colocar uma chamada de função dentro da condição final:

for( vector<...>::size_type i = 0; i < v.size(); ++i ) { // vector size may grow.
   if( ... ) v.push_back( i ); // contrived, but possible
}

// note: this code may be replaced by a std::for_each construct, the previous can't.
for( vector<...>::size_type i = 0, elements = v.size(); i != elements; ++i ) {
}

Por que é bodering você? Essas duas alternativas não vejo estar fazendo o mesmo. Se está fazendo um número fixo de iterações, enquanto o outro é dependente do corpo loops.

Outra colud alternativa ser

for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
 //loop body
}

A menos que você precisa a variável do laço fora do loop, a segunda abordagem é preferível.

Iterators vai realmente dar-lhe tão bom ou melhor desempenho. (Houve um grande fio de comparação sobre comp.lang.c ++. Moderado de alguns anos atrás).

Além disso, eu usaria

int i = 0;

Ao invés do construtor como a sintaxe que você está usando. Enquanto válida, não é idiomática.

Um pouco alheios:

Aviso:. Comparação entre inteiro assinado e sem assinatura

O tipo correto para índices de matriz e vetor é size_t .

Strictly falando, em C ++ é ainda std::vector<>::size_type.

Incrível como muitos desenvolvedores C / C ++ ainda receber um presente errado.

Vamos ver o código gerado (eu uso MSVS 2008, com otimização completa).

a.

int i(0), iMax(vec.size());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
  //loop body
}

O laço for produz 2 instruções assembler.

b.

for( int i(0);i < vec.size(); ++i)
{
  //loop body
}

O laço for produz 8 instruções assembler. vec.size () é embutido com sucesso.

c.

for (std::vector<int>::const_iterator i = vec.begin(), e = vec.end(); i != e; ++i)
{
  //loop body
}

O laço for produz 15 instruções assembler (tudo está embutido, mas o código tem um monte de saltos)

Assim, se seu aplicativo é o desempenho uso crítico a). Caso contrário, b) ou c).

Deve-se notar que os exemplos iterator:

for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
 //loop body
}

poderia invalidar o iterador loop 'que' se o corpo do loop causa o vetor para realocar. Assim, não é equivalente a

for (int i=0;i<vec.size();++i){
 //loop body
}

onde o corpo de loop adiciona elementos para VEC.

Pergunta simples:? Você está modificando vec no circuito

resposta a esta pergunta vai levar a sua resposta também.

JRH

É muito difícil para um compilador para içar a chamada vec.length() no conhecimento seguro de que é constante, a menos que ele fica embutido (que espero que muitas vezes!). Mas pelo menos i definitivamente deve ser declarado no segundo estilo "b", mesmo que as necessidades de chamadas length ser "manualmente" hasteada fora do laço!

Este é preferível:

typedef vector<int> container; // not really required,
                               // you could just use vector<int> in for loop

for (container::const_iterator i = v.begin(); i != v.end(); ++i)
{
    // do something with (*i)
}
  • posso dizer imediatamente que o vector não está sendo atualizado
  • qualquer um pode dizer o que está acontecendo aqui
  • Eu sei quantas voltas
  • v.end() retorna o ponteiro um após o último elemento então não há nenhuma sobrecarga de verificar o tamanho
  • fácil de atualização para diferentes recipientes ou tipos de valor

(b) não irá calcular / chamar a função de cada vez.

- começam trecho ----

Curva Código Invariant Motion: GCC inclui ciclo invariante movimento código como parte do seu ciclo optimizador, bem como na sua passagem eliminação redundância parcial. Essa otimização remove instruções de loops, que calcular um valor que não muda ao longo da vida de um loop.

--- trecho final -

Mais otimizações para gcc:

https://www.in.redhat.com/software /gnupro/technical/gnupro_gcc.php3

Por que não evitar a questão inteiramente com BOOST_FOREACH

#include <boost/foreach.hpp>

std::vector<double> vec;

//...

BOOST_FOREACH( double &d, vec)
{
    std::cout << d;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top