2016-07-07 4 views
0

Рассмотрим следующий фрагмент кода:Получить ссылку на неинициализированным станд :: элемент вектора

void ProcessVect(std::vector<double>& myInVect) 
{ 
    std::vector<double> myOutVect(myInVect.size()); 

    for (size_t i =0; i < myInVect.size(); i++) 
    { 
     ProcessValue(myInVect[i], myOutVect[i]); // ProcessValue(double in, double& out); 
    } 

    DoSomething(myOutVect); 
} 

Этот код работает, но имеет тот недостаток, что myOutVect инициализируется нулями первого и чем переписывается значение, рассчитанное в ProcessValue ,

Я должен сделать это для больших векторов и скорости. Невозможно изменить функцию ProcessValue для принятия векторов.

Теперь мой вопрос: Есть ли способ передать ссылку на неинициализированный векторный элемент на функцию?

Я пробовал myOutVect.reserve() без инициализации myOutVect, но это дает мне ошибку "index out of bounds".

Другие решения моей проблемы, конечно, также приветствуются.

+3

Эта нулевая инициализация не сильно влияет на вашу производительность. –

+1

['std :: transform'] (http://en.cppreference.com/w/cpp/algorithm/transform) с [' std :: back_inserter'] (http://en.cppreference.com/w/cpp/iterator/back_inserter) (и 'reserve')? Но я сомневаюсь, что это действительно важно. – BoBTFish

+1

* Я должен сделать это для больших векторов и вопросов скорости * - Вы действительно измерили производительность? – PaulMcKenzie

ответ

0

std::vector::reserve действительно похоже на хороший способ сделать это.

Возможно, вы получили свое исключение, потому что reserve выделяет только память, это не изменяет длину. Поэтому вам все равно придется звонить push_back или emplace_back.

Попробуйте это:

void ProcessVect(std::vector<double>& myInVect) 
{ 
    std::vector<double> myOutVect; 
    myOutVect.reserve(myInVect.size()); 

    for (size_t i =0; i < myInVect.size(); i++) 
    { 
     double v; 
     ProcessValue(myInVect[i], v); // ProcessValue(double in, double& out); 
     myOutVect.push_back(v); 
    } 

    DoSomething(myOutVect); 
} 

EDIT: Как Маттео отметил в комментариях, это решение может быть хуже, чем нулевой инициализации. Быстрая проверка шахты на Compiler Explorer показывает, что она зависит от компилятора, некоторые из них всегда проверяют емкость, некоторые ее оптимизируют. В целом, я могу только рекомендовать запустить ваш профайлер и посмотреть, что быстрее в ваших условиях!

+2

Для векторов примитивных типов 'push_back' обычно хуже нуля инициализации - нулевая инициализация может выполняться в действительно быстром проходе, а затем сохранение элементов сводится к разыменованию указателя; OTOH, 'push_back' требует проверки векторной емкости каждый раз, увеличивая ее и корректируя логический размер. В плотных циклах это часто бывает очень плохо (потери в регистрах, обращения к памяти, кэше команд и ветвях могут быть значительными). –

-1

Возможно создание статического вектора, поэтому данные будут считываться из exe-файла в память один раз. статический вектор myOutVect (100000); например:
static vector a(10000); static_cast< vector < int >> (a); auto itr = a.begin(); * itr = 10;

+0

это просто альтернатива – Alexandr

+1

Что делать, если есть 100 001 элемент? – Donnie

0

Один полезный трюк, чтобы просто избежать воссоздавать (и rezeroing) результирующий вектор, передавая ее в качестве аргумента:

void ProcessVect(std::vector<double>& myInVect, std::vector<double>& myOutVect) 
{ 
    assert(myInVect.size()==myOutVect.size()); 
    for (size_t i =0; i < myInVect.size(); i++) 
    { 
     ProcessValue(myInVect[i], myOutVect[i]); // ProcessValue(double in, double& out); 
    } 
    DoSomething(myOutVect); 
} 

Абонент может затем использовать один и тот же выходной вектор через повторных вызовов.

Если вы находитесь в классе, вы можете сделать его членом класса, но будьте осторожны, что он делает ProcessVect менее надежным потоком.

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

Смежные вопросы