priority_queue у меня используется для хранения заданий (BaseTask), упорядочиваемых по времени (BaseTask::get_scheduled_time).
Поэтому, как я понимаю, у меня остается выбор:
1) Использовать указатели
2) shared_ptr
3) unique_ptr (больше всего подходит по смыслу, потому что указатели на задачи нет смысла шарить)
Но с unqiue ptr такая беда...
Подскажите, как такое "идиоматически выдержанно " делать в C++ 14?
На Stackoverflow в принципе ответили, на ваш вопрос. Еще можно снять константность со ссылки результата `queue::top()`. Это должно быть безопасно, если не планируется менять ключ объекта по которому упорядочены элементы priority queue:
Здравствуйте, PM, Вы писали:
PM>На Stackoverflow в принципе ответили, на ваш вопрос. Еще можно снять константность со ссылки результата `queue::top()`. Это должно быть безопасно, если не планируется менять ключ объекта по которому упорядочены элементы priority queue:
std::move изменяет значение верхнего элемента heap-структуры что нарушает инвариант и можешь сломать pop()
Re[3]: C++ 14 нельзя priority_queue<unique_ptr<T>> ....
Здравствуйте, PM, Вы писали:
PM>Еще можно снять константность со ссылки результата `queue::top()`. Это должно быть безопасно, если не планируется менять ключ объекта по которому упорядочены элементы priority queue:
А с чем будет сравниваться следующий вставляемый элемент в очередь? Очередь с приоритетами, это по сути — heap. При вставке нового элемента сравнение может происходить с любым из элементов уже размещенных в куче, в том числе и с "головой".
Re: C++ 14 нельзя priority_queue<unique_ptr<T>> ....
Тут возникает встречный вопрос: если у вас BaseTask не нужно ни с кем разделять, то зачем вам обязательно извлекать BaseTask из priority_queue перед использованием, а не после? Вот так же пример со Stackoverflow будет работать:
#include <queue>
int main ()
{
std::priority_queue<std::unique_ptr<int>> queue;
queue.push(std::unique_ptr<int>(new int(42)));
const std::unique_ptr<int> & myInt = queue.top();
return *myInt;
}
Т.е. получили константную ссылку на unique_ptr<BaseTask>, поработали с ним, затем вызывали pop у priority_queue.
Если же BaseTask обязательно нужно извлечь из очереди перед использованием, a shared_ptr<BaseTask> по каким-то причинам не устраивает, то напрашивается хранение в очереди не unique_ptr<BaseTask> напрямую, а специальной обертки. Что-то типа:
Здравствуйте, 5.März, Вы писали:
5M>Здравствуйте, PM, Вы писали:
PM>>На Stackoverflow в принципе ответили, на ваш вопрос. Еще можно снять константность со ссылки результата `queue::top()`. Это должно быть безопасно, если не планируется менять ключ объекта по которому упорядочены элементы priority queue:
5M>std::move изменяет значение верхнего элемента heap-структуры что нарушает инвариант и можешь сломать pop()
Это зависит от компаратора, используемого в heap. В моем примере инвариант не нарушается.
Re[3]: C++ 14 нельзя priority_queue<unique_ptr<T>> ....
Здравствуйте, Videoman, Вы писали:
PM>>Еще можно снять константность со ссылки результата `queue::top()`. Это должно быть безопасно, если не планируется менять ключ объекта по которому упорядочены элементы priority queue:
V>А с чем будет сравниваться следующий вставляемый элемент в очередь? Очередь с приоритетами, это по сути — heap. При вставке нового элемента сравнение может происходить с любым из элементов уже размещенных в куче, в том числе и с "головой".
Если оператор сравнения, используемый для упорядочивания элементов кучи не нарушает инвариант, то это безопасно:
Здравствуйте, PM, Вы писали:
PM>Если оператор сравнения, используемый для упорядочивания элементов кучи не нарушает инвариант, то это безопасно...
Вы правы, но поскольку автор не привел всего кода, лучше такие экзотические примеры не рассматривать. Автор явно пытается перемещать сразу весь объект. Что после этого будет? — остается только гадать.
Re: C++ 14 нельзя priority_queue<unique_ptr<T>> ....
Здравствуйте, MarcoPolo, Вы писали:
MP>Подскажите, как такое "идиоматически выдержанно " делать в C++ 14?
Проблема, как я понимаю, в том, что top не получается достать из очереди с отдачей владения. Можно на top посмотреть, и можно его уничтожить.
По идее это же просто очередные проявления того старого косяка контейнеров stl, что в них нельзя хранить объекты, копии которых различимы.
Ну проще всего складывать в очередь что-то такое, что можно копировать.
Например, можно складывать задания в лежащий рядом с очередью std::list, а вместо указателя на задание, использовать его итератор в списке.
Тогда, вынутые и обработанные задания грохнет из списка тот, кто вынимает, а те, что остались почему-то в очереди, грохнет при разрушении всего этого хозяйства сам список...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: C++ 14 нельзя priority_queue<unique_ptr<T>> ....
Здравствуйте, Erop, Вы писали:
E>По идее это же просто очередные проявления того старого косяка контейнеров stl, что в них нельзя хранить объекты, копии которых различимы.
Не уверен, что в данном случае это косяк. Очередь использует компаратор элементов, чтобы показать тебе top. Если поменяешь top или украдешь его кишки, то поломаешь инвариант контейнера.
Re[3]: C++ 14 нельзя priority_queue<unique_ptr<T>> ....
Здравствуйте, andyp, Вы писали:
A>Не уверен, что в данном случае это косяк. Очередь использует компаратор элементов, чтобы показать тебе top. Если поменяешь top или украдешь его кишки, то поломаешь инвариант контейнера.
Ну это особенность проектирования. Что мешало добавить в очередь не только возможность создавать элемент на месте, но и вынимать его с возможностью дальнейшего move или swap, не особо понятно.
Но в STL это последовательное решение было, которое потом ослабили всякими там emplace, но всё равно методы вроде datach_top как-то не особо во всех контейнерах предусмотрели
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: C++ 14 нельзя priority_queue<unique_ptr<T>> ....
E>Ну это особенность проектирования. Что мешало добавить в очередь не только возможность создавать элемент на месте, но и вынимать его с возможностью дальнейшего move или swap, не особо понятно. E>Но в STL это последовательное решение было, которое потом ослабили всякими там emplace, но всё равно методы вроде datach_top как-то не особо во всех контейнерах предусмотрели
Дизайн STL, на сколько помню, предполагал что элементы контейнера будут по крайней мере Regular, что в последнее время все чаще не выполняется. Суют абы что
Ведь и контейнер перестает быть Regular, если его элементы не являются объектами регулярных типов. Я бы всё-таки смотрел на emplace как на возможность оптимизации, а не как на возможность хранения move only типов. Вроде ж в стандарте нигде не написано, что копи-конструктор вектора может отваливаться в зависимости от типа элементов.
Ну и штуки типа detach_top, помимо логарифмической сложности, что в общем не беда, именно поэтому не предусмотрены имхо — не собираются отказываться от регулярности элементов.