Я хочу сравнить два std::weak_ptr или один std::weak_ptr и один std::shared_ptr на равенство.
Я хочу знать, является ли объект, на который указывает каждый из weak_ptr/shared_ptr, одинаковым. Сравнение должно давать отрицательные результаты не только в том случае, если адреса не совпадают, но и в том случае, если базовый объект был удален, а затем случайно восстановлен с тем же адресом.
Итак, в основном, я хочу, чтобы это утверждение сохранялось, даже если распределитель резервирует тот же адрес:
auto s1 = std::make_shared<int>(43);
std::weak_ptr<int> w1(s1);
s1.reset();
auto s2 = std::make_shared<int>(41);
std::weak_ptr<int> w2(s2);
assert(!equals(w1,w2));
Шаблоны weak_ptr не предоставляют операторов равенства, и, как я понял, это для уважительная причина.
Таким образом, наивная реализация будет выглядеть так:
template <typename T, typename U>
inline bool naive_equals(const std::weak_ptr<T>& t, const std::weak_ptr<U>& u)
{
return !t.expired() && t.lock() == u.lock();
}
template <typename T, typename U>
inline bool naive_equals(const std::weak_ptr<T>& t, const std::shared_ptr<U>& u)
{
return !t.expired() && t.lock() == u;
}
Если срок действия первого weak_ptr истек, он возвращает 0. Если нет, я обновляю weak_ptr до shared_ptr и сравниваю адреса.
Проблема в том, что я должен заблокировать weak_ptr дважды (один раз)! Боюсь, это занимает слишком много времени.
Я придумал это:
template <typename T, typename U>
inline bool equals(const std::weak_ptr<T>& t, const std::weak_ptr<U>& u)
{
return !t.owner_before(u) && !u.owner_before(t);
}
template <typename T, typename U>
inline bool equals(const std::weak_ptr<T>& t, const std::shared_ptr<U>& u)
{
return !t.owner_before(u) && !u.owner_before(t);
}
Который проверяет, не находится ли блок владельца u «до» t и t не перед u, поэтому t == u.
Это работает так, как я задумал? Всегда ли два weak_ptr, созданные из разных shared_ptr, сравниваются как неравные таким образом? Или я что-то пропустил?
Изменить. Почему я вообще хочу это сделать? Я хочу иметь контейнер с общими указателями, и я хочу раздавать ссылки на объекты в нем. Я не могу использовать итераторы, так как они могут быть признаны недействительными. Я мог бы раздавать (целочисленные) идентификаторы, но это приводит к проблемам с уникальностью, требует типа карты и усложняет операции поиска/вставки/удаления. Идея состоит в том, чтобы использовать std::set и выдавать сами указатели (заключенные в класс-оболочку) в качестве ключей, чтобы клиенты могли использовать weak_ptr для доступа к объектам в наборе.
owner_before()
существует. В моем случае сравнение блоков управления было единственным разумным ответом. - person vinipsmaker   schedule 08.10.2020