Проверка позиции вновь добавленного unique_ptr в priority_queue - PullRequest
2 голосов
/ 17 февраля 2020

Я переключаю свой дизайн на использование интеллектуальных указателей, и я столкнулся с проблемой с std :: priority_que

У меня был метод, который вставляет новую задачу в очередь и сигнализирует, если новая задача приземлилась в верхней части it:

bool foo(SchedulerTask* task)
{
  eventList_.push(task);
  return task == eventList_.top();
}

После упаковки SchedulerTask в unique_ptr я столкнулся с проблемой проверки его приоритета в контейнере. После перемещения объекта в очередь я не смог использовать его снова для сравнения. Я закончил с кэшированием члена компаратора и сравнил его с верхним объектом:

bool foo(std::unique_ptr<SchedulerTask> task)
{
  const auto prio = task->getCycle(); // my priority_queue compares objects by getCycle() value

  eventList_.push(std::move(task));

  return prio >= eventList_.top()->getCycle();;
}

Можно ли сделать это лучше?

Ответы [ 4 ]

1 голос
/ 17 февраля 2020

Как намекнул @Sam Varschavchik, вы можете сравнить его с необработанным указателем. Т.е. вы бы сделали что-то вроде:

bool foo (std::unique_ptr<SchedulerTask> task) {
  auto const * taskPtr = task.get();
  eventList_.push(std::move(task));
  return taskPtr == eventList_.top().get();
}
0 голосов
/ 18 февраля 2020

Использовать общий указатель

Вы можете использовать тип общего указателя владения. То есть просто используйте вместо std::shared_ptr. У этого не будет той же самой проблемы вообще. Код выглядит почти так же, как и раньше:

bool foo(std::shared_ptr<SchedulerTask> task)
{
  eventList_.push(task);
  return task == eventList_.top();
}

Использование прокси с идентификатором

Ваша проблема в основном такова: как только вы перемещаете уникальный указатель в контейнер, вы больше не можете его идентифицировать , Следовательно, другое решение может быть , чтобы придерживаться std::unique_ptr, но добавить механизм уникальной идентификации. Это может быть объект прокси-типа:

struct SchedulerTaskInfo {
  std::unique_ptr<SchedulerTask> task_;
  int id_;
};

Теперь вы можете сравнить, используя id_:

bool foo(SchedulerTaskInfo task)
{
  eventList_.push(std::move(task));
  return task.id_ == eventList_.top().id_;
}

Вы можете даже создать operator== на прокси, если Вы хотели.

0 голосов
/ 17 февраля 2020

Вы также можете проверить перед добавлением задачи, будет ли она закончена впереди:

// Assumes eventList_ uses a stateless Comparator of type Cmp
bool foo(std::unique_ptr<SchedulerTask> task)
{
  bool greater = Cmp{}(eventList_.top(), task); 

  eventList_.push(std::move(task));

  return greater;
}

Конечно, это может быть неверным результатом в многопоточном контексте, так как eventList_ может меняться между чек и push. Но то же самое может произойти и после проверки, и это должно быть зафиксировано замком.

0 голосов
/ 17 февраля 2020

Два печальных способа решения этой проблемы:

1.

bool foo(std::unique_ptr<SchedulerTask> task)
{
  SchedularTask* tmp = task.get();
  eventList_.push(std::move(task));
  return tmp == eventList_.top().get();
}

2.

bool foo(std::unique_ptr<SchedulerTask> task)
{
  std::unique_ptr<SchedularTask> tmp(task.get());
  eventList_.push(std::move(task));
  bool ret = (tmp == eventList_.top());
  tmp.release();
  return ret;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...