Как только счетчик указателя shared_ptr достигает нуля, он автоматически освобождает объект, на который указывает:

auto r = make_shared(42); // объект int, на который указывает r,

                               // имеет одного владельца

r = q; // присвоение r переводит этот указатель на другой адрес

// приращение счетчика владельцев объекта, на который указывает q

// уменьшение счетчика владельцев объекта, на который указывает r

// объект, на который указывал r, не имеет более владельцев;

// он освобождается автоматически

Здесь резервируется переменная типа int, а ее адрес сохраняется в указателе r. Затем указателю r присваивается новое значение. В данном случае r — единственный указатель типа shared_ptr, указывающий на этот объект. В результате присвоения r = q переменная int автоматически освобождается.

Будет ли использован счетчик или другая структура данных для отслеживания количества указателей на совместно используемый объект, зависит от реализации компилятора. Главное то, что класс отслеживает количество указателей shared_ptr на тот же объект и автоматически освобождает его в подходящий момент.

Указатель shared_ptr автоматически удаляет свои объекты…

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

Деструкторы обычно освобождают ресурсы, зарезервированные объектом. Например, конструкторы класса string (как и другие его члены) резервируют память для содержания составляющих ее символов. Деструктор класса string освобождает эту память. Точно так же некоторые функции класса vector резервируют память для хранения элементов вектора. Деструктор класса vector удаляет эти элементы и освобождает используемую ими память.

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

…и автоматически освобождает их память

Тот факт, что класс shared_ptr автоматически освобождает динамические объекты, когда они больше не нужны, существенно облегчает использование динамической памяти. Рассмотрим, например, функцию, которая возвращает указатель shared_ptr на динамически созданный объект типа Foo, который может быть инициализирован аргументом типа Т:

// функция factory() возвращает указатель shared_ptr на динамически

// созданный объект

shared_ptr factory(Т arg) {

 // обработать аргумент соответствующим образом

 // shared_ptr позаботится об освобождении этой памяти

 return make_shared(arg);

}

Функция factory() возвращает указатель shared_ptr, гарантирующий удаление созданного ею объекта в подходящий момент. Например, следующая функция сохраняет указатель shared_ptr, возвращенный функцией factory(), в локальной переменной:

void use_factory(Т arg) {

 shared_ptr p = factory(arg);

 // использует p

} // p выходит из области видимости; память, на которую он указывал,

  // освобождается автоматически

Поскольку указатель p является локальным для функции use_factory(), он удаляется по ее завершении (см. раздел 6.1.1). Когда указатель p удаляется, осуществляется декремент его счетчика ссылок и проверка. В данном случае p — единственный указатель на объект в памяти, возвращенный функцией factory(). Поскольку указатель p выходит из области видимости, объект, на который он указывает, удаляется, а память, в которой он располагался, освобождается.

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

shared_ptr use_factory(Т arg) {

 shared_ptr p = factory(arg);

 // использует p

 return p; // при возвращении p счетчик ссылок увеличивается

Перейти на страницу:

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