Может ли истекший weak_ptr отличаться от неинициализированного?

Например:

std::weak_ptr<int> wp1(std::make_shared<int>());
std::weak_ptr<int> wp2;

assert(PointsToValidOrExpiredObject(wp1));
assert(!PointsToValidOrExpiredObject(wp2));

Возможна ли такая функция?

Случай использования: Конструктор класса принимает std::weak_ptr<Foo> как зависимость. Передача истекшего объекта в порядке (может произойти в определенных рабочих процессах), но передача null означает, что программист что-то забыл. Я бы хотел проверить это как часть проверки параметров конструктора.

Ответы

Ответ 1

std::weak_ptr::owner_before может различать слабые указатели, которые пусты и истекли. Поэтому вы можете реализовать PointsToValidOrExpiredObject как:

template <typename T>
bool PointsToValidOrExpiredObject(const std::weak_ptr<T>& w) {
    return w.owner_before(std::weak_ptr<T>{}) ||
           std::weak_ptr<T>{}.owner_before(w);
}

Демо.

Относительно первоначальной неопределенности, которую я имел о истечении срока действия weak_ptr, все еще сохраняющего право собственности: теперь я уверен, что общие требования к безопасности потоков истекший weak_ptr продолжает иметь такое же право собственности. В противном случае уничтожение последнего оставшегося shared_ptr в потоке A должно было бы, по-видимому, изменить состояние одного /some/all weak_ptr, которое разделяет право собственности на shared_ptr. Если поток B одновременно изучал состояние такого weak_ptr, тогда у вас была бы гонка данных, введенная реализацией библиотеки, которая вообще запрещена.