смена векторов первым указателем - PullRequest
3 голосов
/ 25 октября 2010

Когда я использую вектор для хранения некоторых данных, я обычно обращаюсь к этим данным по указателю первой записи вектора. потому что это быстрее, чем метод at (). Но я понимаю, что когда я вставляю блок данных, скажем, массив в конец вектора, указатель первой записи изменяется. Это может быть реализовано в стеке, но если я добавлю массив по одному элементу за раз с помощью push_back, первый указатель не изменится. Так почему это так? Должен ли я беспокоиться об использовании указателя для доступа к элементам?

Вот пример кода для тех, кто хочет проверить:

int arrayLen = 500000;
 vector<int> vint = vector<int>(2000,0);
 int * firstEntry = &vint[0];

 int * iarray = new int[arrayLen];
 for(int i = 0; i< arrayLen; i++)
 {
  iarray[i] = i;
 }
 vint.insert(vint.end(),iarray,iarray+arrayLen);
 cout << firstEntry << "," << &vint[0] << endl; // They ar not equal;

         // reset the vector
 vint.clear();
 vint.resize(2000,0);
 firstEntry = &vint[0];

 for(int i = 0; i< arrayLen; i++)
 {
  vint.push_back(iarray[i]);
  if(firstEntry != &vint[0])
   cout << firstEntry << "," << &vint[0] <<","<< i << endl;
 }// nothing  is written

 cout << firstEntry << "," << &vint[0] << endl; // now they are equal;

Ответы [ 3 ]

4 голосов
/ 25 октября 2010

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

При условии, что вы не добавляете больше данных в свой вектор, вам не нужно беспокоиться о указателе наданные в векторе являются недействительными.Вы можете ожидать, когда дальнейший push_back () вызовет изменение размера, проверив, vint.capacity () == vint.size ().Вы также можете избежать использования недействительного указателя, всегда используя обновленный указатель через & vint [0] (или & vint.at () для проверки диапазона), а не копируя его.

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

vint.reserve(vint.size() + 2000);
for(int i=0; i<2000; ++i) {
    vint.push_back(i);
}

было бы хорошо, но

for(int i=0; i<2000; ++i) {
    vint.reserve(vint.size() + 1);
    vint.push_back(i);
}

было бы перетаскиванием производительности, так как вы постоянно спрашиваетеОС для увеличения объема памяти и выполнения операции копирования с каждой итерацией.

2 голосов
/ 25 октября 2010

векторы могут перераспределяться в большую область памяти в куче, когда вы добавляете элементы.Вы должны использовать [] вместо at(), если вы хотите более высокую производительность, но тогда вы должны быть уверены, что ваши показатели находятся в диапазоне: это обычно легко гарантировать.Это очень плохая практика, и совершенно необязательно отдавать предпочтение кэшированию и индексированию из указателя начала вектора: просто включите оптимизатор и убедитесь, что вы не используете какой-либо режим отладки в режиме «проверенного итератора» STL (если он имеетодин, например, Visual C ++), и производительность в любом случае будет одинаковой.

Если вы знаете максимальный размер, до которого может расти вектор, то вы можете предварительно изменить его размер с помощью Reserve ().

1 голос
/ 25 октября 2010

Используйте reserve() для предотвращения многократного выделения памяти перед вставкой множества элементов.

Затем получите «первый указатель», который не должен изменяться, если вы правильно зарезервировали правильное количество элементов.

Но почему бы вам не использовать begin()?Операторы * и -> работают над этим, вы знаете ...

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