vector :: reserve (), кажется, не выделяет место - PullRequest
3 голосов
/ 24 января 2011

Прикрепленный код содержит три вызова std :: vector :: assign ().Перед первым вызовом вызывается std :: vector :: reserve () для выделения соответствующего объема памяти, а затем заполняется вектор.Второй вызов метод assign () не вызывает метод Reserve () перед заполнением второго вектора, поэтому я ожидаю, что по крайней мере одно распределение произойдет во время этого вызова метода assign ().Третий вызов метода assign () используется для повторного заполнения первого вектора новыми данными.Четвертый блок в коде выделяет массив int с помощью new и заполняет его.

Я бы ожидал, что первый, третий и четвертый блоки будут одинаковыми по производительности, тогда как второй блок должен потребовать дополнительного времени из-зараспределение (ы) требуется.На самом деле я обнаружил, что первый и второй блоки занимают одинаковое количество времени, а третий и четвертый блоки работают значительно быстрее (~ 30%).Мне кажется, что вызов import () на самом деле не выделяет требуемое пространство, но выделение откладывается до вызова assign ().

Я проверил это на двух платформах: Windows Vistaскомпилирован с использованием компилятора Visual C ++ 2010 и SUSE linux с использованием компилятора gcc 4.3.2.Я пробовал разные уровни оптимизации (включая отсутствие оптимизации) и продолжаю видеть то же самое поведение.Любые идеи, почему Reserve () не делает то, что я ожидаю?Если то, что я вижу, является правильным поведением, то какой смысл резервировать ()?

Спасибо, Джош

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

int main()
{
  int     len=1E8, nloops=100;
  clock_t start, stop;
  double  wr=0.0, wor=0.0, wc=0.0, pb=0.0;

  printf("Number of values tested = %d\n", len);
  printf("Number of loops = %d\n", nloops);

  std::vector<int> vec1a, vec1b;
  for(int i=0; i<len; i++) vec1a.push_back(i);
  for(int i=len; i>0; i--) vec1b.push_back(i);

  for(int i=0; i<nloops; i++)
  {
    std::vector<int>  vec2, vec3;
    int              *vec4;

//First block
    vec2.reserve(len);
    start = clock();
    vec2.assign(vec1a.begin(), vec1a.end());
    stop = clock();
    wr += ((double)(stop-start))/((double)(CLOCKS_PER_SEC));

//Second block
    start = clock();
    vec3.assign(vec1a.begin(), vec1a.end());
    stop = clock();
    wor += ((double)(stop-start))/((double)(CLOCKS_PER_SEC));

//Third block
    vec2.clear();
    start = clock();
    vec2.assign(vec1b.begin(), vec1b.end());
    stop = clock();
    wc += ((double)(stop-start))/((double)(CLOCKS_PER_SEC));

//Fourth block
    start = clock();
    vec4 = new int[len];
    for(int j=0; j<len; j++) vec4[j] = vec1a[j];
    stop = clock();
    pb += ((double)(stop-start))/((double)(CLOCKS_PER_SEC));
    delete []vec4;
  }

  printf("With reserve()    = %10.4lE\n", wr);
  printf("Without reserve() = %10.4lE\n", wor);
  printf("With clear()      = %10.4lE\n", wc);
  printf("newed int array   = %10.4lE\n", pb);

  return 0;
}

Ответы [ 2 ]

4 голосов
/ 24 января 2011

Учитывая, что источник вектора находится в заголовочном файле, вы можете искать, что делает .assign. Внутри присвоения он распределяет столько предметов, сколько ему нужно все сразу. Шаблон достаточно умен, чтобы знать, что ему нужно 1E8, когда вы делаете vec2.assign(vec1a.begin(), vec1a.end())

Если вы действительно хотите проверить его, выполните итерацию по каждому элементу и используйте push_back вместо assign ()

Добавление

Просто для пояснения: в стеке вызовов для .assign () он вычисляет новую емкость и вызывает _Grow_to (MSVC ++ 10). По сути, .assign () делает резерв.

2 голосов
/ 24 января 2011

Это не объясняет ваши результаты, но вам может быть интересно узнать, что ни reserve, ни new[] фактически не выделяют память.Вместо этого они просто выделяют адресное пространство внутри вашего процесса, который будет иметь фактические страницы ОЗУ, зафиксированные диспетчером виртуальной памяти, только если и когда они будут использованы (а страницы будут фиксироваться по одной за раз, часть блока можетсовершено, а часть нет).

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