Ответ 1
Он использует распределитель, который был предоставлен ему в качестве второго параметра шаблона. Так вот. Скажем, что это в push_back, пусть t
- объект, который нужно нажать:
...
if(_size == _capacity) { // size is never greater than capacity
// reallocate
T * _begin1 = alloc.allocate(_capacity * 2, 0);
size_type _capacity1 = _capacity * 2;
// copy construct items (copy over from old location).
for(size_type i=0; i<_size; i++)
alloc.construct(_begin1 + i, *(_begin + i));
alloc.construct(_begin1 + _size, t);
// destruct old ones. dtors are not allowed to throw here.
// if they do, behavior is undefined (17.4.3.6/2)
for(size_type i=0;i<_size; i++)
alloc.destroy(_begin + i);
alloc.deallocate(_begin, _capacity);
// set new stuff, after everything worked out nicely
_begin = _begin1;
_capacity = _capacity1;
} else { // size less than capacity
// tell the allocator to allocate an object at the right
// memory place previously allocated
alloc.construct(_begin + _size, t);
}
_size++; // now, we have one more item in us
...
Что-то вроде этого. Распределитель будет заботиться о распределении памяти. Он сохраняет шаги выделения памяти и построения объекта в эту память отдельно, поэтому он может предварительно распределять память, но еще не вызывает конструкторы. Во время перераспределения вектор должен заботиться об исключениях, которые бросают конструкторы копирования, что несколько усложняет этот вопрос. Выше всего лишь фрагмент кода псевдокода, а не настоящий код и, вероятно, содержит много ошибок. Если размер превышает емкость, он просит распределитель выделить новый больший блок памяти, если не тогда, он просто конструируется в ранее выделенном пространстве.
Точная семантика этого зависит от распределителя. Если это стандартный распределитель, конструкция будет делать
new ((void*)(_start + n)) T(t); // known as "placement new"
И выделение allocate
просто получит память из ::operator new
. destroy
будет вызывать деструктор
(_start + n)->~T();
Все, что абстрагируется за распределителем, и вектор просто использует его. Распределитель стека или объединения может работать совершенно иначе. Некоторые ключевые моменты о vector
, которые важны
- После вызова
reserve(N)
у вас может быть до N элементов, вставленных в ваш вектор, не рискуя перераспределением. До тех пор это до тех пор, покаsize() <= capacity()
, ссылки и итераторы к его элементам остаются в силе. - Векторное хранилище смежное. Вы можете рассматривать & v [0] как буфер, содержащий столько элементов, которые у вас есть в вашем векторе.