Как слабый_птр знает, что общие ресурсы истекли?

Учитывая следующий код:

#include <memory>
#include <iostream>

using namespace std;

struct MySharedStruct
{
int i;
};

void print_value_of_i(weak_ptr<MySharedStruct> weakPtr)
{
if (shared_ptr<MySharedStruct> sp = weakPtr.lock())
{ cout << "Value of i = " << sp->i << endl; }
else
{ cout << "Resource has expired"; }
}

int main()
{
shared_ptr<MySharedStruct> sharedPtr(new MySharedStruct() );
sharedPtr->i = 5;

weak_ptr<MySharedStruct> weakPtr;
weakPtr = sharedPtr;

print_value_of_i(weakPtr);

sharedPtr.reset(new MySharedStruct() ); // <<----- How does weak_ptr know it has expired after this line executes?
sharedPtr->i = 10;

print_value_of_i(weakPtr);

return 0;
}

Как работает weak_ptr знаю, что истек, учитывая ресурс, который shared_ptr была ссылка была по существу заменена другим ресурсом? Что значит weak_ptr следить, чтобы точно знать, что старый общий ресурс был уничтожен и заменен новый общий ресурс? Пример определения (если применимо) таких методов lock в weak_ptr будет оценено.

11

Решение

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

Для x86 и x86-64 они используют атомарные операции и не имеют явной блокировки (без мьютекса или спин-блокировки). Хитрость реализации — это специальная функция без блокировки (язык кода для занятого вращения) atomic_conditional_increment это только увеличивает счетчик ссылок на объект, если он не равен нулю. Используется при реализации weak_ptr::lock функция, чтобы справиться с гонкой, когда более чем один поток пытается создать shared_ptr из того же weak_ptr со счетчиком ссылок на объекты равным нулю. Увидеть http://www.boost.org/doc/libs/1_52_0/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp

Сам блок управления распределяется между shared_ptrи weak_ptrи имеет другой счетчик ссылок для себя, так что он остается в живых до тех пор, пока не будет выпущена последняя ссылка на него.

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

10

Другие решения

Короткий ответ

Я подозреваю, что большинство реализаций достигают этого, имея общий блок управления, который как weakPtr а также sharedPtr Ссылаться на. когда sharedPtr сбрасывается, это уменьшает use_count в блоке управления, что weakPtr можно использовать для проверки правильности указателя.

Длинный ответ

Но я думаю, что это может варьироваться в зависимости от реализации. Вот пример того, что должно произойти в стандарте C ++ 11:

shared_ptr<MySharedStruct> sharedPtr(new MySharedStruct());

в 20.7.2.2.1, sharedPtr построен с владением данными данными.

weak_ptr<MySharedStruct> weakPtr;
weakPtr = sharedPtr;

в 20.7.2.3.1, weakPtr строится, а затем присваивается значение sharedPtr, После назначения weakPtr а также sharedPtr Теперь поделитесь правами собственности на данные данные.

sharedPtr.reset(new MySharedStruct());

в 20.7.2.2.4, reset(Y*) эквивалентно shared_ptr(Y*).swap(*this), Другими словами, sharedPtr меняет его содержимое на временное shared_ptr который владеет новыми данными.

После обмена sharedPtr будут владеть новыми данными, а временные будут делиться собственностью старых данных с weakPtr,

в 20.7.2.2.2, временный затем разрушается:

  • Поскольку временный владелец старых данных и не разделяет это право собственности с другим shared_ptr Например, он удаляет старые данные.
  • Все экземпляры, которые делят собственность с временным shared_ptr сообщит use_count() это на единицу меньше его предыдущего значения.

Это означает, что weakPtr.use_count() == 0,

if (shared_ptr<MySharedStruct> sp = weakPtr.lock()) {
cout << "Value of i = " << sp->i << endl;
} else {
cout << "Resource has expired";
}

в 20.7.2.3.5, призвание lock эквивалентно

expired() ? shared_ptr<T>() : shared_ptr<T>(*this)

…а также expired() эквивалентно

use_count() == 0

…что значит lock вернет пустой shared_ptr,

9

По вопросам рекламы [email protected]