Почему в weak_ptr нет оператора сравнения ==?

Если у меня есть vector<weak_ptr<Type>>, я не могу использовать vector::erase(remove()) для удаления нужного weak_ptr, потому что у него нет оператора сравнения==.

Лямбда-предикат должен быть передан в remove_if в vector::erase(remove_if()) для сравнения базовых исходных указателей, доступ к которым осуществляется через weak_ptr::_Get()

_Get() начинается с подчеркивания и заглавной буквы, что означает, что он зарезервирован для реализации и не предназначен для доступа пользователя.

Понятно, что weak_ptr не должны были храниться таким образом, но почему?


Я думал об использовании vector<weak_ptr<>> для хранения weak_ptrs в дочернем классе только некоторых объектов, которые у меня есть в классе менеджера, которые нуждаются в дальнейшей обработке и, таким образом, с помощью lock()ing убеждаюсь, что они не были удалены. в управляющем классе (в многопоточном приложении).

Менеджер предупреждает дочерний класс о создании и удалении объекта, сохраняя vector<weak_ptr<>> актуальным.


person Deadfish    schedule 13.04.2018    source источник
comment
Что, по вашему мнению, будет сравнивать ==? Тот самый weak_ptr? Или разные weak_ptr для одного и того же объекта? Или разные weak_ptr для разных объектов с одинаковым значением?   -  person Galik    schedule 13.04.2018
comment
Связано: stackoverflow.com/questions/12301916/ и это содержит ссылку на open-std.org/ jtc1/sc22/wg21/docs/papers/2004/n1590.html   -  person Barmar    schedule 13.04.2018
comment
Возможный дубликат Equality-compare std::weak_ptr   -  person Joseph D.    schedule 13.04.2018
comment
Также можете ли вы объяснить код с использованием std::remove_if, который не сработал?   -  person Galik    schedule 13.04.2018
comment
Ваш предикат может выполнять a.lock() == b.lock() и не полагаться на детали внутренней реализации.   -  person Igor Tandetnik    schedule 13.04.2018
comment
@IgorTandetnik, но это будет означать, что любые указатели с истекшим сроком действия одинаковы, что, возможно, не является исторической правдой. Во многих случаях это может быть приемлемо, но если вы попытаетесь удалить все обработчики для определенного объекта с истекшим сроком действия, вы удалите слишком много.   -  person Gem Taylor    schedule 13.04.2018
comment
Я думал, что вы сможете получить хэш из слабого ptr, но, похоже, это не поддерживается. Вы можете взять хэш интеллектуального указателя при вставке слабого указателя, но это кажется дополнительной работой.   -  person Gem Taylor    schedule 13.04.2018
comment
@GemTaylor Все дескрипторы с истекшим сроком действия одинаковы. Нет (стандартного, портативного) способа отличить их друг от друга; они не следят за своим происхождением. Если вы считаете, что вам это нужно, вам нужно сохранить какую-то форму вместе с экземпляром weak_ptr.   -  person Igor Tandetnik    schedule 13.04.2018
comment
@IgorTandetnik Да, это явно опубликованный интерфейс. Внутренне, конечно, они различны, если они ведут к разным фактическим объектам, даже если срок действия объектов истек. Я признаю, что мне трудно представить себе реальный случай, в котором мне было бы не все равно.   -  person Gem Taylor    schedule 13.04.2018
comment
Я думаю, единственная другая проблема заключается в том, что есть работа, связанная с блокировкой хорошего weakptr. Если бы я просматривал список weakptr, чтобы найти совпадение, эта стоимость могла бы быть значительной по сравнению с простым сравнением значений. И я не могу хранить их в каком-либо хэше или наборе на основе их текущего значения блокировки, так как значение блокировки уменьшается до нуля.   -  person Gem Taylor    schedule 13.04.2018
comment
Некоторые реализации могут даже не помнить адрес объекта, который сейчас уничтожается, при уже освобожденной памяти. А в C/C++ с таким указателем ничего не сделаешь.   -  person curiousguy    schedule 27.04.2018


Ответы (1)


Вы можете использовать идиому стереть-удалить с явным предикатом.

Например:

#include <functional>
#include <iostream>
#include <memory>
#include <vector>

using std::cout;
using std::make_shared;
using std::remove_if;
using std::vector;
using std::weak_ptr;

int main()
{
  auto p7 = make_shared<int>(7);
  auto p8 = make_shared<int>(8);
  auto p10 = make_shared<int>(10);
  auto p11 = make_shared<int>(11);

  vector<weak_ptr<int>> v;

  v.push_back(p7);
  v.push_back(p8);

  {
    auto p9 = make_shared<int>(9);
    v.push_back(p9);
    // p9 dtor'd here
  }

  v.push_back(p10);
  v.push_back(p11);
  p8.reset(new int{18}); // old p8 dtor'd here
  p10 = make_shared<int>(110); // old p10 dtor'd here

  // Only 7 and 11 left.

  v.erase(remove_if(v.begin(), v.end(), [](auto w){ if (auto spt = w.lock()) return false; else return true; }), v.end() );
  for (auto w : v)
  {
    cout << "Value is ";
    if (auto s = w.lock())
    {
      cout << *s << "\n";
    }
    else
    {
      cout << "MISSING!\n";
    }
  }
}
person Eljay    schedule 13.04.2018