Литмир - Электронная Библиотека
A
A

}

Подразумевается, что функции-члену

copy()
доступны
sz
элементов как в аргументе
arg
, так и в векторе, в который он копируется. Для того чтобы обеспечить это, мы сделали функцию-член
copy()
закрытой. Ее могут вызывать только функции, являющиеся частью реализации класса vector. Эти функции должны обеспечить совпадение размеров векторов.

Конструктор копирования устанавливает количество элементов (

sz
) и выделяет память для элементов (инициализируя указатель
elem
) перед копированием значений элементов из аргумента
vector
.

vector::vector(const vector& arg)

// размещает элементы, а затем инициализирует их путем копирования

       :sz(arg.sz), elem(new double[arg.sz])

{

  copy(arg);

}

Имея конструктор копирования, мы можем вернуться к рассмотренному выше примеру.

vector v2 = v;

Это определение инициализирует объект

v2
, вызывая конструктор копирования класса
vector
с аргументом
v
. Если бы объект класса
vector
содержал три элемента, то возникла бы следующая ситуация:

Программирование. Принципы и практика использования C++ Исправленное издание - _197.png

Теперь деструктор может работать правильно. Каждый набор элементов будет корректно удален. Очевидно, что два объекта класса

vector
теперь не зависят друг от друга, и мы можем изменять значения элементов в объекте
v
, не влияя на содержание объекта
v2
, и наоборот. Рассмотрим пример.

v.set(1,99);  // устанавливаем v[1] равным 99

v2.set(0,88); // устанавливаем v2[0] равным 88

cout << v.get(0) << ' ' << v2.get(1);

Результат равен

0
0
.

Вместо инструкции

vector v2 = v;

мы могли бы написать инструкцию

vector v2(v);

Если объекты

v
(инициализатор) и
v2
(инициализируемая переменная) имеют одинаковый тип и в этом типе правильно реализовано копирование, то приведенные выше инструкции эквивалентны, а их выбор зависит от ваших личных предпочтений. 

18.2.2. Копирующее присваивание

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Копирование векторов может возникать не только при их инициализации, но и при присваивании. Как и при инициализации, по умолчанию копирование производится поэлементно, так что вновь может возникнуть двойное удаление (см. раздел 18.2.1) и утечка памяти. Рассмотрим пример.

void f2(int n)

{

  vector v(3); // определяем вектор

  v.set(2,2.2);

  vector v2(4);

  v2 = v;      // присваивание: что здесь происходит?

  // ...

}

Мы хотели бы, чтобы вектор

v2
был копией вектора
v
(именно так функционирует стандартный класс
vector
), но поскольку в нашем классе
vector
смысл копирования не определен, используется присваивание по умолчанию; иначе говоря, присваивание выполняется почленно, и члены
sz
и
elem
объекта
v2
становятся идентичными элементам
sz
и
elem
объекта
v
соответственно.

Эту ситуацию можно проиллюстрировать следующим образом:

Программирование. Принципы и практика использования C++ Исправленное издание - _198.png

При выходе из функции

f2()
возникнет такая же катастрофа, как и при выходе из функции
f()
в разделе 18.2, до того, как мы определили копирующий конструктор: элементы, на которые ссылаются оба вектора,
v
и
v2
, будут удалены дважды (с помощью оператора
delete[]
). Кроме того, возникнет утечка памяти, первоначально выделенной для вектора
v2
, состоящего из четырех элементов. Мы “забыли” их удалить. Решение этой проблемы в принципе не отличается от решения задачи копирующей инициализации (см. раздел 18.2.1). Определим копирующий оператор присваивания.

class vector {

  int sz;

  double* elem;

  void copy(const vector& arg); // копирует элементы из arg

                                // в *elem

public:

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

  // ...

};

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

 // делает этот вектор копией вектора a

{

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

  for (int=0; i<asz; ++i)

    p[i]=a.elem[i];             // копируем элементы

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

  elem = p;                     // теперь можно обновить elem

  sz = a.sz;

240
{"b":"847443","o":1}