Можно ли улучшить производительность кода с помощью функции Reserve () перед перемещением вектора с большим размером в вектор с меньшей емкостью? - PullRequest
4 голосов
/ 30 апреля 2019

заранее извините, если этот вопрос достаточно неполный, неясный или дублированный (это мой первый вопрос здесь). Изучая семантику перемещения и работая над небольшим проектом для моего курса ООП, я наткнулся на вопрос, на который я не могу ответить сам. Насколько я знаю, std :: move () работает путем преобразования l-значений в значения r, но давайте предположим, что мы перемещали вектор с большим количеством элементов во второй вектор, имеющий емкость 1. Могу ли я использовать резерва ( ) избежать много автоматических перераспределений памяти второго вектора, или использование резерва () не имеет никакого эффекта из-за того, что std :: move () перемещает значения r во второй вектор? Простая реализация моего вопроса может быть найдена ниже.

#include <iostream>
#include <vector>
#include <algorithm>
int main() {
    std::vector<int> first (1000000);
    std::vector<int> second (1);
    std::fill(first.begin(),first.end(),7);
    second.reserve(1000000);//is this needed??
    second=std::move(first);
    return 0;
}

Ответы [ 2 ]

5 голосов
/ 30 апреля 2019

Нет, это не нужно, и это почти наверняка преждевременная оптимизация.

Вектор действительно может быть представлен 3 указателями (или двумя указателями и смещением, или одним указателем и двумя смещениями ... но это не так часто, так что для остальной части моего объяснения я представлю, что векторы представлены тремя указателями).

  1. Один указатель указывает на начало памяти, которой он управляет.
  2. Один указатель указывает на один конец элемента, который был вставлен в него.
  3. Один указатель указывает на конец памяти, которой он управляет.

Конструктор перемещения std::vector<int> a = std::move(b); можно реализовать, просто взяв эти три указателя из b, установив для них какое-либо простое в создании значение (nullptr в качестве значения часового, означающего «Я пустой», для пример) и тогда все будет сделано.

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

Таким образом, ваш reserve вызов в лучшем случае оптимизируется компилятором в бездействие, а в худшем случае вызывает ненужное выделение памяти. Не хорошо!

4 голосов
/ 30 апреля 2019

Пожалуйста, взгляните на этот пост: Вектор STL: перемещение всех элементов вектора

std::move() - это решение O(1). Когда вы используете ith для векторов, перемещенный вектор теперь пуст, а новый содержит все элементы перемещенного. Методы reserve() ничего не сделают в этом случае (но в других случаях это очень полезно).

Вы можете использовать метод std::swap(), который также не требует использования метода reserve().

...