Вектор [] и копирование - PullRequest
       30

Вектор [] и копирование

0 голосов
/ 11 апреля 2010

Что быстрее и / или вообще лучше?

vector<myType> myVec;
int i;
myType current;

for( i = 0; i < 1000000; i ++ )
{
 current = myVec[ i ];
 doSomethingWith( current );
 doAlotMoreWith( current );
 messAroundWith( current );
 checkSomeValuesOf( current );
}

или

vector<myType> myVec;
int i;

for( i = 0; i < 1000000; i ++ )
{
 doSomethingWith( myVec[ i ] );
 doAlotMoreWith( myVec[ i ] );
 messAroundWith( myVec[ i ] );
 checkSomeValuesOf( myVec[ i ] );
}

В настоящее время я использую первое решение. В действительности происходит миллионы вызовов в секунду, и каждое сравнение / перемещение в одном бите вызывает проблемы с производительностью.

Ответы [ 4 ]

11 голосов
/ 11 апреля 2010

Первая версия может быть излишне дорогой, поскольку она основывается на создании копии объекта в векторе. Если myType не является каким-то очень маленьким и простым объектом, например int, хранение ссылки может быть лучшей идеей. Он также должен быть объявлен , когда вам нужно , и не раньше, чтобы ограничить проблемы с наложением имен, которые могут , иначе компилятор будет выдавать менее эффективный код:

vector<myType> myVec;
for(int i = 0; i < 1000000; i ++ )
{
 myType& current = myVec[ i ];
 doSomethingWith( current );
 doAlotMoreWith( current );
 messAroundWith( current );
 checkSomeValuesOf( current );
}

Одним из преимуществ создания копии вместо использования ссылки является то, что это может привести к тому, что компилятор загружает объект в регистр, а не считывает его из памяти при каждом обращении. Так что обе версии стоит попробовать.

Любое, конечно, рекомендация "Копировать против справочника" также применима к каждой из ваших функций Они принимают аргумент по значению или по ссылке? В зависимости от того, что они делают с ним и как определяется myType, один может быть быстрее другого.

Вторая версия имеет недостатки, поскольку она (если компилятор не может ее оптимизировать) требует, чтобы объект просматривался в памяти каждый раз. В зависимости от вашей реализации STL, могут также быть некоторые издержки из-за проверки границ на operator[].

Сначала необходимо создать временное имя, которое затем передается каждой из ваших функций. Вопрос в том, должно ли это временное значение иметь тип значения (myType) или ссылочный тип (myType& / const myType&)

Другой вариант, который может заслуживает изучения, - это помещение каждого вызова функции в отдельный цикл. Это в некоторой степени вредит локальности данных, но если некоторые функции используют много локальных данных, они могут работать лучше. Это может также играть лучше с кешем инструкций.

Но на самом деле производительность чрезвычайно сложна. Кэширование, выполнение вне порядка, точная семантика myType (особенно его конструктор копирования и размер) и количество оптимизаций, выполняемых компилятором, все нам неизвестны. Таким образом, мы не можем дать вам надежный ответ.

Угадай, кто может: твой компилятор. Написать тест. Попробуйте оба. Время результаты. Выберите более быстрый.

1 голос
/ 11 апреля 2010

Помимо избежания множественного доступа к одному и тому же индексу и использования ссылки во избежание копирования, вы можете использовать в своих функциях соглашение о вызовах fastcall . Он дает указание компилятору передавать параметры в регистрах, когда это возможно, вместо , помещая их в стек.

Однако, быстрый вызов не стандартизирован, поэтому он зависит от поставщика.

0 голосов
/ 11 апреля 2010

С точки зрения форматирования я бы предложил следующее (объявите в точке инициализации, используйте const myType &):

vector myVec;
for(int i = 0; i < 1000000; i++){
 const myType& current = myVec[i];
 doSomethingWith(current);
 doAlotMoreWith(current);
 messAroundWith(current);
 checkSomeValuesOf(current);
}

Однако, с точки зрения вашего исходного вопроса, использование временной переменной с именем current будет, по крайней мере, столь же быстрым, как и использование myVec[i] каждый раз. Возможно, однако, что оптимизирующий компилятор удалит избыточные поиски в myVec (т.е. используя ваше решение о назначении временного) ... в общем, если вы вызываете функцию-член, объявленную "const" несколько раз, без использования неконстантных Функция-член, компилятор может создавать временные и выполнять вызов только один раз, сохраняя результат в локальном временном.

0 голосов
/ 11 апреля 2010

Зависит от того, что получает оператор присваивания для вашего типа. Надеюсь, вы переходите по ссылке на эти функции? Но что касается всех вопросов производительности, если это важно для вас, протестируйте свой конкретный случай самостоятельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...