LINUX.ORG.RU

C++ vector


0

0

Здраствуйте.
Хочу узнать как лучше "проходить по вектору", сам всегда делал так :

for ( unsigned int i = 0 ; i < vec_buf.size() ; i++ )
{
    delaem_chto_to ( vec_buf[i] );
}

Есть ли какие нибудь недостатки или скрытые ошибки в данном
использовании вектора?
Спасибо.
anonymous

вопрос идеологии/удобства.

1.
std::vector<type>::iterator cur = vec_buf.begin(),
vec_end = vec_buf.end();

for( ; cur!=vec_end; ++cur )
  delaem_chto_to ( *cur );

2.
struct delaem_chto_to {
  void operator() ( type& t ) {...}
};

std::for_each( vec_buf.begin(), vec_buf.end(), delaem_chto_to() );

итог в общем одинаков

lb
()

std::for_each() - самый идеологически правильный вариант.
Если лениво писать функтор, то можно
for(std::vector<>::iterator it = vec_buf.begin(); it != vec_buf.end(); ++it)
delaem_chtoto(*it);

Так гораздо быстрее, т.к. инкремент итератора выполняется в общем случае быстрее,
чем operator[]

Flogger_d
()
Ответ на: комментарий от lb

:( удобочитаемость теряется ... а для меня это очень важно. А скорость? Есть польза от такого использования. Или итог не одинаков, а идентичен?

anonymous
()
Ответ на: комментарий от Flogger_d

А почему ++it а почему плюсуется до? В чем разница с it++?

Можно и так чтоб не вызывать постоянно vec_buf.end() :

for(std::vector<>::iterator it = vec_buf.begin(), vec_end = vec_buf.end(); it != vec_end; ++it)

anonymous
()
Ответ на: комментарий от anonymous

См. первый ответ:
std::vector<type>::iterator it = vec_buf.begin();
std::vector<type>::iterator end = vec_buf.end();
for(;it != end; ++it) do_smt(*it);

++it предпочтительнее чем it++ т.к. не нужно предыдущее
значение, которое возвращается постфиксной формой.
Для таких циклов как правило нужно писать именно префиксную форму.

Flogger_d
()
Ответ на: комментарий от Flogger_d

А, тьфу, дошло ... сорри не так подумал. Так а как скорость? Я не представляю как проверить разницу, поэтому и спрашиваю.

anonymous
()
Ответ на: комментарий от anonymous

Ну, например, делаешь два варианта - один с [], и другой с итераторами.
И запускай на количество циклов, порядка 10^7. С помощью команды time
получишь время работы каждого варианта и сравнишь.

Flogger_d
()
Ответ на: комментарий от anonymous

А просто посмотреть в исходники и почитать доку по STL никак? Там приводятся теоретические оценки сложности для различных действий над контейнерами.

phoenix ★★★★
()
Ответ на: комментарий от Flogger_d

#include <vector>

void do_chto_to ( int &g )
{    
    g = 0; g += 10;
}

int main ()
{
    std::vector<int> test;
    for ( int i = 0 ; i < 100 ; i++ )
        test.push_back ( i );

    for ( unsigned long cx = 0 ; cx < 5000 ; cx ++ )
        for ( unsigned int i = 0 ; test.size() ; i++ )
            do_chto_to ( test[i] );

    return EXIT_SUCCESS;
}


Валится в Segmentation fault... его аналог : 
    std::vector<int>::iterator it = test.begin();
    std::vector<int>::iterator end = test.end();

    for ( unsigned long cx = 0 ; cx < 5000 ; cx ++ )
        for ( ; it != end ; ++it )
            do_chto_to ( *it );
Работает ок. Что я тут напутал?

anonymous
()
Ответ на: комментарий от Flogger_d

Ага спасибо... а вот и результаты :
1 - []
2 - итератор
С -О0 и циклом 500000 :
1:
real    0m5.598s
user    0m5.533s
sys     0m0.015s
2:
real    0m0.016s
user    0m0.014s
sys     0m0.002s

C -O1 :
real    0m0.909s
user    0m0.889s
sys     0m0.003s

real    0m0.015s
user    0m0.007s
sys     0m0.002s

C -O2 :
real    0m0.389s
user    0m0.379s
sys     0m0.000s

real    0m0.005s
user    0m0.001s
sys     0m0.004s
И наконец C -O3 :
real    0m0.088s
user    0m0.082s
sys     0m0.002s

real    0m0.007s
user    0m0.005s
sys     0m0.001s
Выводы : использование итераторов предпочтительнее. Всем спасибо большое!!!

anonymous
()
Ответ на: комментарий от anonymous

Тест очень подозрительный. Разницу в 10 раз можно объяснить
только кривизной кода. У меня получается примерно одна скорость
в обоих вариантах.

#include "time.h"
#include <vector> 
#include <iostream>

int main (int argc, char * argv[])
{
  using namespace std;
  vector <int> vL(20000000,1);
  fill(vL.begin(), vL.end(), 1);

  clock_t start, end;
  double cpu_time_used;

  start = clock();
  for (unsigned int iL=0, stopL=vL.size (); iL<stopL; ++iL)
    vL[iL]*=100;
  end = clock();
  cout<<"Time []" <<((double) (end - start)) / CLOCKS_PER_SEC<< endl;;
  fill(vL.begin(), vL.end(), 1);

  start = clock();
  for ( vector<int>::iterator itL=vL.begin(); itL != vL.end(); )
    {
      *itL++ *= 100;
    }; //for
  end = clock();
  cout<<"Time *" <<((double) (end - start)) / CLOCKS_PER_SEC<< endl;;

  fill(vL.begin(), vL.end(), 1);
  start = clock();
  for (unsigned int iL=0, stopL=vL.size (); iL<stopL; ++iL)
    vL[iL]*=100;
  end = clock();
  cout<<"Time []" <<((double) (end - start)) / CLOCKS_PER_SEC<< endl;;

  fill(vL.begin(), vL.end(), 1);

  start = clock();
  for ( vector<int>::iterator itL=vL.begin(); itL != vL.end(); )
    {
      *itL++ *= 100;
    }; //for
  end = clock();
  cout<<"Time *" <<((double) (end - start)) / CLOCKS_PER_SEC<< endl;;
  return 0;
};

g++ -O3 -funroll-all-loops -o time time.cc && ./time
Time []0.26
Time *0.25
Time []0.23
Time *0.25

anonymous
()
Ответ на: комментарий от anonymous

Внимательнее смотрите пожалуйста мой пост ... 
С -О0 и циклом 500000 :
1:
real    0m5.598s
user    0m5.533s
sys     0m0.015s

И наконец C -O3 :
real    0m0.088s
user    0m0.082s
sys     0m0.002s

Так вот .. теперь откомпильте свой код с -О0

anonymous
()
Ответ на: комментарий от anonymous

Зачем сравнивать производительность кода собранного без оптимизации?
Да и все равно 10 кратной разницы не получается:

  g++ -O0 -o time time.cc && ./time
Time []1.42
Time *2.53
Time []1.4
Time *2.53

gcc version 3.3.5 (Debian 1:3.3.5-13)

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.