Программирование. Принципы и практика использования C++ Исправленное издание, стр. 262
{ if (newalloc<=space) return; // размер не уменьшается T* p = alloc.allocate(newalloc); // выделяем новую память for (int i=0; i<sz; ++i) alloc.construct(&p[i],elem[i]); // копируем for (int i=0; i<sz; ++i) alloc.destroy(&elem[i]); // уничтожаем alloc.deallocate(elem,space); // освобождаем старую память elem = p; space = newalloc;}Мы перемещаем элемент в новый участок памяти, создавая копию в неинициализированной памяти, а затем уничтожая оригинал. Здесь нельзя использовать присваивание, потому что для таких типов, как
stringИмея функции
reserve()vector<T,A>::push_back()template<class T, class A>void vector<T,A>::push_back(const T& val){ if (space==0) reserve(8); // начинаем с памяти для 8 элементов else if (sz==space) reserve(2*space); // выделяем больше памяти alloc.construct(&elem[sz],val); // добавляем в конец // значение val ++sz; // увеличиваем размер}Аналогично можно написать функцию
vector<T,A>::resize()template<class T, class A>void vector<T,A>::resize(int newsize, T val = T()){ reserve(newsize); for (int i=sz; i<newsize; ++i) alloc.construct(&elem[i],val); // создаем for (int i = newsize; i<sz; ++i) alloc.destroy(&elem[i]); // уничтожаем sz = newsize;}Обратите внимание на то, что, поскольку некоторые типы не имеют конструкторов по умолчанию, мы снова предоставили возможность задавать начальное значение для новых элементов.
Другое новшество — деструктор избыточных элементов при уменьшении вектора. Представьте себе деструктор, превращающий объект определенного типа в простой набор ячеек памяти.
19.4. Проверка диапазона и исключения
Мы проанализировали текущее состояние нашего класса
vectoroperator[]template<class T, class A> T& vector<T,A>::operator[](int n){ return elem[n];}Рассмотрим следующий пример:
vector<int> v(100);v[–200] = v[200]; // Ой!int i;cin>>i;v[i] = 999; // повреждение произвольной ячейки памятиЭтот код компилируется и выполняется, обращаясь к памяти, не принадлежащей нашему объекту класса
vectorvectorat()struct out_of_range { /* ... */ }; // класс, сообщающий об ошибках,// связанных с выходом за пределы допустимого диапазонаtemplate<class T, class A = allocator<T> > class vector { // ... T& at(int n); // доступ с проверкой const T& at(int n) const; // доступ с проверкой T& operator[](int n); // доступ без проверки const T& operator[](int n) const; // доступ без проверки // ...};template<class T, class A > T& vector<T,A>::at(int n){ if (n<0 || sz<=n) throw out_of_range(); return elem[n];}template<class T, class A > T& vector<T,A>::operator[](int n)// как прежде{ return elem[n];}Итак, мы можем написать следующую функцию:
void print_some(vector<int>& v){ int i = –1; cin >> i; while(i!= –1) try { cout << "v[" << i << "]==" << v.at(i) << "\n";