Скачиваний:
190
Добавлен:
05.07.2021
Размер:
16.53 Mб
Скачать

17. Особенности создание пользовательского класса умного указателя (smart pointer). Перечень необходимых условий для реализации пользовательского класса умного указателя. Пример использования.

Интеллектуальный указатель (smart pointer) действует, как обычный указатель, но с важным дополнением: автоматически удаляет объект, на который он указывает. Умный указатель обычно является шаблонным классом. Чаще всего умный указатель инкапсулирует семантику владения ресурсом. В таком случае он называется владеющим указателем. Владеющие указатели применяются для борьбы с утечками памяти и висячими ссылками.

Реализации класса SmartPointer должна предусматривать условие, что если, уничтожается последняя ссылка на объект, то происходит уничтожение данного объекта. Это достигается, тем, что создается дополнительно структура, в которой наряду с указателем на динамический объект хранится так же счетчик числа указателей, «прикрепленных» к этому объекту. Динамический созданный объект может быть уничтожен только в том случае, если счетчик ссылок на этот объект станет равным нулю.

Пример реализации пользовательского умного указателя:

18. Особенности копирования, присваивания и удаления объектов при создании пользовательского класса умного указателя (smart pointer). Пример использования.

При использовании копирующего конструктора происходит увелечение счётчика ссылок. Пример кода копирующего конструктора:

Перегружаем оператор присвоения. Теперь при присвоении смарт поинтер проверяет существует ли поинтер на объект. Если да, то уменьшаем кол-во ссылок и проверяем, равен ли счётчик ссылок нулю или меньше, если да, то удаляем поинтер. После чего присоединяем передаваемый объект к новому указателю и увеличиваем счётчик. Пример кода перегузки оператора присвоения:

При вызове деструктора происходит уменьшение счётчика, если счётчик будет равен нулю или меньше, происходит освобождение выделенной памяти:

19. Размещающий оператор new (placement new). Передача ему объекта nothrow. Пример использования.

Существует особая форма оператора new, называемая placement new. Данный оператор не выделяет память, а получает своим аргументом адрес на уже выделенную каким-либо образом память. Происходит размещение (инициализация) объекта путем вызова конструктора, и объект создается в памяти по указанному адресу.

Int* p1 = new int; // Если при вызове этого оператора будет невозможно выделить динамическую память, то будет вызвано исключение типа bad_alloc.

Int* p1 = new (nothrow) int; //Если при вызове этого оператора будет невозможно выделить динамическую память, то new не вызовет никакого исключения.

Выражение размещающего оператора new позволяет передать дополнительные аргументы. В данном случае передается определенный библиотекой объект nothrow.

Передача объекта nothrow оператору new указывает, что он не должен передавать исключения. Если эта форма оператора new окажется неспособна зарезервировать требуемый объем памяти, она возвратит нулевой указатель

Тип nothrow определен в заголовке new.

Размещающий new обычно применяется не для встроенных типов. Работа «обычного» new состоит из двух операций: выделение памяти и вызов конструктора для конструирования объекта. Память размещающий new не выделяет, но вызов конструктора выполняется и в этом случае. Но тогда возникает проблема вызова деструктора — для «обычных» динамических объектов деструктор вызывался автоматически операцией delete. Однако для размещающего new операцию delete выполнять не нужно, поэтому и деструктор автоматически не вызывается!