Reputation: 975
I want to implement a timer queuing system using the C++ STL priority_queue container adapter.
My problem is that I want to occasionally cancel a timer, however there are no interfaces that enable me to easily delete an item in the priority_queue that is not the top item.
Any suggestions?.
Thank you for your help.
Upvotes: 13
Views: 15967
Reputation: 3
I had the same requirement. If you have the freedom to change the container, the one that can solve this problem is std::set (no duplicates allowed) or std::multiset.
Both are ordered and can erase an element logarithmic in container size (see the documentation for details). For help in deleting in multi set you might want to see this.
See the difference std::set vs std::priority_queue before deciding.
Upvotes: 0
Reputation: 9508
I had the exact same scenario once and did the following:
std::priority_queue
contained only the time to sort by and an index to a std::vector<Handler>
(in my case Handler
was boost::function
, but could as well be pointer to interface or function)boost::function
call clear()
, if using pointers, set it to zero)1 To make finding a free index fast, I used a separate std::stack
of indices. When adding a timer and that stack is empty, add at the end of vector; otherwise pop the top index and use it.
2 Here's the point when you push the index to the free indices stack
The whole thing is somewhat tricky and error-prone, especially if your timer callbacks need to add or cancel timers. Here's a link to my canceling timer class described above, this code is public domain
Upvotes: 10
Reputation: 254691
Despite what some other answers say, it is possible to access the underlying container of any standard container adapter, including priority_queue
, since the container is exposed as a protected member called c
. You can either inherit from priority_queue
and extend the interface, or use dirty tricks such as this to temporarily gain access to a normal priority_queue
.
Upvotes: 4
Reputation: 17430
My problem is that I want to occasionally cancel a timer, however there are no interfaces that enable me to easily delete an item in the priority_queue that is not the top item.
If canceling a timer happens often, then you need to use some different structure. std::map isn't that bad too, though cost of delete_min would go up.
If canceling a timer happens rarely, then marking the element as deleted (and ignoring it during ::pop) might do the trick.
Upvotes: 3
Reputation: 47770
I'm afraid STL priority_queue
doesn't offer such functionality. You can write your own heap class (which is not that hard). You could even use the std::xxx_heap
functions by dirty tricks like this:
delete_heap(iterator to_delete, iterator heap_begin, iterator heap_end)
{
to_delete->key = something that would compare less to everything; // make sure it gets to the top in the next step
std::push_heap(heap_begin, to_delete+1);
std::pop_heap(heap_begin, heap_end);
}
which will get you O(log n)
delete.
Upvotes: 7
Reputation: 527238
The STL priority_queue container is specifically designed so that only the top item is accessible, so if you need to be able to remove non-top items, you're going to have to find a different class to use.
Upvotes: 2