Получение unique_ptr из очереди приоритетов

Я поддерживаю набор unique_ptr случаи в priority_queue, В какой-то момент я хочу получить первый элемент и удалить его из очереди. Однако это всегда приводит к ошибке компилятора. Смотрите пример кода ниже.

int main ()
{
std::priority_queue<std::unique_ptr<int>> queue;
queue.push(std::unique_ptr<int>(new int(42)));

std::unique_ptr<int> myInt = std::move(queue.top());
return 1;
}

Это приводит к следующей ошибке компилятора (gcc 4.8.0):

uptrtest.cpp: In function ‘int main()’: uptrtest.cpp:6:53: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’    std::unique_ptr<int> myInt = std::move(queue.top());
^ In file included from /usr/include/c++/4.8/memory:81:0,
from uptrtest.cpp:1: /usr/include/c++/4.8/bits/unique_ptr.h:273:7: error: declared here
unique_ptr(const unique_ptr&) = delete;
^

Изменение кода для использования queue как в этот вопрос решает проблему, и код компилируется просто отлично.

Нет ли способа сохранить unique_ptrв priority_queue или я что-то упустил?

6

Решение

std::priority_queue::top() возвращает константную ссылку, поэтому вы не можете ее переместить. Глядя на открытый интерфейс priority_queue нет способа получить неконстантную ссылку, которую вы можете переместить (что является обязательным для unique_ptr, он не имеет конструктора копирования).

Решение: замещать unique_ptr с shared_ptr чтобы иметь возможность скопировать их (а не просто переместить их).

Или, конечно, использовать другой вид контейнера вообще (но если вы выбрали priority_queue во-первых, это, вероятно, не приемлемо для вас).

Вы также можете использовать «взлом защищенного члена» для доступа к защищенному члену. c (лежащий в основе контейнер), но я бы не рекомендовал его, это довольно грязно и вполне вероятно UB.

8

Другие решения

Я согласен, это невероятно раздражает. Почему это позволяет мне std::move элементы в очередь, тогда не дайте мне способа их переместить? У нас больше нет копии оригинала, поэтому мне нужен неконстантный объект, когда я делаю top() а также pop(),

Решение: простираться std::priority_queue, добавив метод pop_top() это делает оба одновременно. Это должно сохранить любой порядок очереди. Это зависит от C ++ 11, хотя. Следующая реализация работает только для компиляторов gcc.

template<typename _Tp, typename _Sequence = std::vector<_Tp>,
typename _Compare = std::less<typename _Sequence::value_type> >
class priority_queue: std::priority_queue<_Tp, _Sequence, _Compare> {
public:
typedef typename _Sequence::value_type value_type;
public:

#if __cplusplus < 201103L
explicit
priority_queue(const _Compare& __x = _Compare(),
const _Sequence& __s = _Sequence()) :
std::priority_queue(__x, __s) {}
#else
explicit
priority_queue(const _Compare& __x, const _Sequence& __s) :
std::priority_queue<_Tp, _Sequence, _Compare>(__x, __s) {}

explicit
priority_queue(const _Compare& __x = _Compare(), _Sequence&& __s =
_Sequence()) :
std::priority_queue<_Tp, _Sequence, _Compare>(__x, std::move(__s)) {}
#endif

using std::priority_queue<_Tp, _Sequence, _Compare>::empty;
using std::priority_queue<_Tp, _Sequence, _Compare>::size;
using std::priority_queue<_Tp, _Sequence, _Compare>::top;
using std::priority_queue<_Tp, _Sequence, _Compare>::push;
using std::priority_queue<_Tp, _Sequence, _Compare>::pop;

#if __cplusplus >= 201103L

using std::priority_queue<_Tp, _Sequence, _Compare>::emplace;
using std::priority_queue<_Tp, _Sequence, _Compare>::swap;

/**
*  @brief  Removes and returns the first element.
*/
value_type pop_top() {
__glibcxx_requires_nonempty();

// arrange so that back contains desired
std::pop_heap(this->c.begin(), this->c.end(), this->comp);
value_type top = std::move(this->c.back());
this->c.pop_back();
return top;
}

#endif

};
4

По вопросам рекламы [email protected]