Я хочу сравнить два 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.
Это работает так, как я это намерен? Разве два слабых_ptr, созданных из разных shared_ptr, всегда сравниваются как не равные таким образом? Или я что-то пропустил?
Изменить: Почему я хочу это сделать в первую очередь? Я хочу иметь контейнер с общими указателями, и я хочу передать ссылки на объекты в нем. Я не могу использовать итераторы, так как они могут быть признаны недействительными. Я мог бы выдавать (целочисленные) идентификаторы, но это приводит к проблемам с уникальностью и потребует тип карты и усложняет операции поиска/вставки/удаления. Идея состоит в том, чтобы использовать std:: set и выдавать сами указатели (капсулируемые в классе-оболочке) в качестве ключей, чтобы клиенты могли использовать weak_ptr для доступа к объектам в наборе.