Учитывая следующий код:
#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
будет оценено.
Блок управления выделяется при 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
При переназначении он указывает на другой блок управления, так что блок управления всегда указывает только на один и тот же объект. Другими словами, в блоке управления нет замены одного объекта другим.
Я подозреваю, что большинство реализаций достигают этого, имея общий блок управления, который как 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
,