Читаем Программирование полностью

Согласно общепринятому соглашению оператор присваивания возвращает ссылку на целевой объект. Смысл выражения *this объяснялся в разделе 17.10. Его реализация является корректной, но, немного поразмыслив, легко увидеть, что мы выполняем избыточные операции выделения и освобождения памяти. Что делать, если целевой вектор содержит больше элементов, чем присваиваемый вектор? Что делать, если целевой вектор содержит столько же элементов, сколько и присваиваемый вектор? Во многих приложениях последняя ситуация встречается чаще всего. В любом случае мы можем просто скопировать элементы в память, уже выделенную ранее целевому вектору.

vector& vector::operator=(const vector& a)

{

  if (this==&a) return *this;  // самоприсваивание, ничего делать

                               // не надо

  if (a.sz<=space) {           // памяти достаточно, новая память

                               // не нужна

  for (int i = 0; i

  sz = a.sz;

  return *this;

}

  double* p = new double[a.sz]; // выделяем новую память

  for (int i = 0; i

                                                 // элементы

  delete[] elem;      // освобождаем старую память

  space = sz = a.sz;  // устанавливаем новый размер

  elem = p;           // устанавливаем указатель на новые

                      // элементы

  return *this;       // возвращаем ссылку на целевой объект

}

В этом фрагменте кода мы сначала проверяем самоприсваивание (например, v=v); в этом случае ничего делать не надо. С логической точки зрения эта проверка лишняя, но иногда она позволяет значительно оптимизировать программу. Эта проверка демонстрирует использование указателя this, позволяющего проверить, является ли аргумент a тем же объектом, что и объект, из которого вызывается функция-член (т.е. operator=()). Убедитесь, что этот код действительно работает, если из него удалить инструкцию this==&a. Инструкция a.sz<=space также включена для оптимизации. Убедитесь, что этот код действительно работает после удаления из него инструкции a.sz<=space.

<p id="AutBody_Root348"><strong>19.2.6. Предыдущая версия класса vector</strong></p>

Итак, мы получили почти реальный класс vector для чисел типа double.

// почти реальный вектор чисел типа double

class vector {

/*

 инвариант:

 для 0<=n

 sz<=space;

 если sz

 для (space–sz) чисел типа double

*/

  int sz;       // размер

  double* elem; // указатель на элементы (или 0)

  int space;    // количество элементов плюс количество слотов

public:

  vector():sz(0),elem(0),space(0) { }

  explicit vector(int s):sz(s),elem(new double[s]),space(s)

  {

    for (int i=0; i

                                        // инициализированы

  }

  vector(const vector&);             // копирующий конструктор

  vector& operator=(const vector&);  // копирующее присваивание

  ~vector() { delete[] elem; }       // деструктор

  double& operator[ ](int n) { return elem[n]; }  // доступ

  const double& operator[](int n) const { return elem[n]; }

  int size() const { return sz; }

  int capacity() const { return space; }

  void resize(int newsize);           // увеличение

  void push_back(double d);

  void reserve(int newalloc);

};

Обратите внимание на то, что этот класс содержит все основные операции (см. раздел 18.3): конструктор, конструктор по умолчанию, копирующий конструктор, деструктор. Он также содержит операции для доступа к данным (индексирование []), получения информации об этих данных (size() и capacity()), а также для управления ростом вектора (resize(), push_back() и reserve()).

<p id="AutBody_Root349"><strong>19.3. Шаблоны</strong></p>

Однако нам мало иметь вектор, состоящий из чисел типа double; мы хотим свободно задавать тип элементов наших векторов. Рассмотрим пример.

vector

vector

vector

vector          // вектор указателей на объекты класса Window

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже