Обычно классы, управляющие ресурсами, расположенными вне его, должны определять функции-члены управления копированием. Как упоминалось в разделе 13.6, такие классы нуждаются в деструкторах, освобождающих зарезервированные объектом ресурсы. Если класс нуждается в деструкторе, он почти наверняка нуждается также в конструкторе копий и операторе присвоения копии.

Чтобы определить эти функции-члены, сначала следует решить, что будет означать копирование объекта данного типа. Вообще, есть два способа: операцию копирования можно определить так, чтобы класс вел себя, как значение или как указатель.

У классов, которые ведут себя, как значения, есть собственное состояние. При копировании объекта как значения копия и оригинал независимы друг от друга. Внесенные в копию изменения никак не влияют на оригинал, и наоборот.

Классы, действующие как указатели, используют состояние совместно. При копировании объектов таких классов копии и оригиналы используют те же данные. Изменения, внесенные в копии, изменяют также оригинал, и наоборот.

Из использованных ранее библиотечных классов поведением, подобным значениям, обладали классы библиотечных контейнеров и класс string. Ничего удивительного, что класс shared_ptr демонстрирует поведение, подобное указателю, как и класс StrBlob (см. раздел 12.1.1). Типы ввода-вывода и класс unique_ptr не допускают ни копирования, ни присвоения, поэтому их поведение не похоже ни на значение, ни на указатель.

Чтобы проиллюстрировать эти два подхода, определим для используемого в упражнениях класса HasPtr функции-члены управления копированием. Сначала заставим класс действовать, как значение, а затем повторно реализуем его в версии, ведущей себя, как указатель.

У класса HasPtr есть два члена типа int и указатель на тип string. Обычно классы непосредственно копируют переменные-члены встроенного типа (кроме указателей); такие члены являются значениями, а следовательно, ведут себя обычно, как значения. Происходящее при копировании указателя-члена определяет то, должно ли у такого класса, как HasPtr, быть поведение, подобное значению или указателю.

Упражнения раздела 13.2

Упражнение 13.22. Предположим, класс HasPtr должен вести себя, как значение. Таким образом, у каждого его объекта должна быть собственная копия строки, на которую указывает объект. Определения функций-членов управления копированием рассматривается в следующем разделе, но уже сейчас известно все необходимое для их реализации. Напишите конструктор копий класса HasPtr и оператор присвоения копии прежде, чем продолжите чтение.

<p><image l:href="#reader.png"/>13.2.1. Классы, действующие как значения</p>

Для обеспечения поведения, подобного значению, у каждого объекта должна быть собственная копия ресурса, которым управляет класс. Это значит, что у каждого объекта класса HasPtr должна быть собственная копия строки, на которую указывает указатель ps. Для реализации поведения, подобного значению, классу HasPtr нужно следующее.

• Конструктор копий, который копирует строку, а не только указатель.

• Деструктор, освобождающий строку.

• Оператор присвоения копии, освобождающий строку существующего объекта и копирующий ее значение в строку правого операнда.

Вот подобная значению версия класса HasPtr:

class HasPtr {

public:

 HasPtr(const std::string &s = std::string()):

  ps(new std::string(s)), i(0) { }

 // у каждого объекта класса HasPtr есть собственный экземпляр строки,

 // на которую указывает указатель ps

 HasPtr(const HasPtr &p) :

  ps(new std::string(*p.ps)), i(p.i) { }

 HasPtr& operator=(const HasPtr &);

 ~HasPtr() { delete ps; }

private:

 std::string *ps;

 int i;

};

Класс достаточно прост, все, кроме оператора присвоения, определено в теле класса. Первый конструктор получает (необязательный) аргумент типа string. Он динамически резервирует собственную копию этой строки и сохраняет ее адрес в указателе ps. Конструктор копий также резервирует собственный экземпляр строки. Деструктор освобождает память, зарезервированную ее конструкторами, выполняя оператор delete для указателя-члена ps.

Подобный значению оператор присвоения копии
Перейти на страницу:

Похожие книги