Я использую std::map
для хранения множества элементов (пар элементов), и у меня есть "небольшое" сомнение. Что более эффективно для итерации всех элементов поверх моих std::map
, iterator
или reverse_iterator
?
Итератор против reverse_iterator
Ответ 1
Это действительно имеет значение? это типы микро оптимизаций, которые вы должны стараться избегать ИМХО. Кроме того, даже если время итерации изменяется для очень большого количества элементов на карте, тот факт, что вы пытаетесь выполнить итерацию по всем элементам такой большой карты, означает, что, скорее всего, вы выбрали неправильную структуру данных.
Ответ 2
Для записи, разыменования reverse_iterator
в std::map
и std::set
контейнеры в два раза медленнее, используя iterator
- с обоими -O3 gcc 3.4.6 и MSVC на процессорах Intel/AMD (почти на 3 раза медленнее на архитектуре PPC). То же самое относится к const_reverse_iterator
vs. const_iterator
. Это связано с тем, что reverse_iterator
фактически указывает на дерево node сразу же после дерева node, которое будет разыменовано, следовательно, дополнительная работа. Итераторы std::vector
демонстрируют гораздо более мягкое различие (reverse_iterator
только на 30% медленнее на PPC, практически неотличимы от Intel/AMD.) Кстати, итератор std::vector
примерно в 20 раз быстрее, чем std::map
или std::set
итератор.
#include <set>
#include <vector>
#include <stdio.h>
#ifdef _WIN32
#include <sys/timeb.h>
#else
#include <sys/time.h>
#endif
#include <time.h>
#define CONTAINER std::set< int >
double
mygettime(void) {
# ifdef _WIN32
struct _timeb tb;
_ftime(&tb);
return (double)tb.time + (0.001 * (double)tb.millitm);
# else
struct timeval tv;
if(gettimeofday(&tv, 0) < 0) {
perror("oops");
}
return (double)tv.tv_sec + (0.000001 * (double)tv.tv_usec);
# endif
}
int main() {
int i, x = 0;
CONTAINER bla;
for (i = 0; i < 10000; bla.insert(bla.end(), i++)) ;
double t1 = mygettime();
for (i = 0; i < 100; ++i) {
for (CONTAINER::iterator it = bla.begin(); it != bla.end(); ++it) {
x ^= *it;
}
}
printf("forward: %f\n", mygettime() - t1);
double t2 = mygettime();
for (i = 0; i < 100; ++i) {
for (CONTAINER::reverse_iterator it = bla.rbegin(); it != bla.rend(); ++it) {
x ^= *it;
}
}
printf("reverse: %f\n", mygettime() - t2);
return 0;
}
Ответ 3
Если вы не профилировали свой код и не обнаружили там существенной разницы, я бы просто не беспокоился об этом.
"Преждевременная оптимизация - это корень все зло". - Дональд Кнут
Ответ 4
Вероятно, не будет никакой разницы. std:: reverse_iterator - это просто шаблон, который переводит ++ в - во время компиляции.
Для вектора или другого непрерывного контейнера хранения онлайнер может взаимодействовать с кешем немного лучше, чем обратный итератор (маловероятно, что вы сможете его обнаружить), но для древовидного контейнера он выиграл ' t вообще не имеет значения - не будет какой-либо локации ссылки на эксплойт.
Ответ 5
Я думаю, что нет смысла использовать reverse_iterator; он противодействует интуитивному.
Это сделает код сложнее понять, кто-то будет смотреть на код и идти "wtf"; и если вам нужно поместить комментарий, чтобы объяснить, почему, это, вероятно, означает, что это не хороший код для начала.
Ответ 6
Мне интересно, нужна ли итерация. Карта содержит пары ключ-значение и обычно используется для поиска. Если вам по-прежнему нужно итерировать карту по некоторым причинам (может быть удаление указателей, содержащихся внутри карты и т.д.), Вы можете использовать std:: for_each, Забудьте о микро-оптимизации, и вы можете попытаться повысить читаемость кода.