Стандарт библиотеки STL требует, чтобы последовательный контейнер под^ держивал три варианта функции insert о: один для вставки значения, другой для вставки множественных копий значения и третий для вставки ряда значений. Далее приведен первый вариант функции insert (). // Вставляет val по адресу р. template <class T, class А> typename RangeArray<T, А>::iterator RangeArray<T, A>::insert(iterator p, const T &val) ¦ { разработка пользовательского контейнера STL 335 iterator q; size_type i, j; // Получает необходимую память. Т *tmp = a.allocate(sizeО + 1); // Копирует существующие элементы в новый массив, // если возможно, вставляет новый элемент. for(i=j=0; i < sizeO; i++, j++) { if(&arrayptr[i] == p) { tmptj] = val; q = &tmp[j]; j++; } tmptj] = arrayptrti]; } // В противном случае новый элемент перемещается в конец, if(р == endO) { tmptj] = val; q = &tmp[j]; } // Корректирует длину len и границы. len++; if (р < &arrayptr [abs( lowerbound) ]) lowerbound—; else upperbound++; // Вызывает деструкторы для элементов старого контейнера, for(size_type i=0; i < size()-l; i++) a.destroy(&arrayptr[i]); // Очищает память, отведенную для старого контейнера. а.deallocate(arrayptr, size()-1); arrayptr = tmp; return q; Первый вариант функции вставляет элемент в позицию, заданную итератором р, передаваемым в ее первом параметре. Функция возвращает итератор указывающий на вставленный элемент. Она выделяет сегмент памяти, д0.! статочный для хранения всех существующих элементов и нового. Затем она копирует существующие элементы во вновь выделенную память, вставляя новый элемент в соответствующее место. Далее функция обновляет переменные-члены len и upperbound или lowerbound соответственно. После этого уничтожаются объекты из исходного контейнера RangeArray, и указателю arrayptr присваивается адрес нового выделенного сегмента памяти. В конце концов, функция возвращает указатель на вставленный объект. Теперь посмотрите внимательно на фрагмент кода, в котором обновляются значения переменных upperbound или lowerbound. Помните, что массив может увеличиваться как в положительном, так и в отрицательном направлениях, в зависимости от того, в какую его часть, положительную или отрицательную, выполняется вставка. Следовательно, нужно определить, куда вставляется новый элемент, и изменить соответствующую границу. Для этого итератор, передаваемый в параметре р, сравнивается с адресом элемента arrayptr [lowerbound]. Если итератор меньше этого элемента, увеличивается отрицательная часть массива, в противном случае — положительная часть. Далее приведены следующие два варианта функции insert (), определенные посредством первого варианта. // Вставляет num копий значения val, начиная с адреса р. void insert(iterator р, int num, const T &val) { for(; num>0; num—) p = insert(p, val) + 1; } // Вставляет ряд элементов, заданный значениями start и stop, по адресу р- void insert(iterator р, iterator start, iterator stop) { while(start != stop) { p = insert(p, *start) + 1; start++; } >
|