I've been working on a parser for commands
(which are fancy wrappers around large arrays of data), and have a queue that unhandled commands reside on. If I need a command, I query it with code like this:
boost::optional<command> get_command() {
if (!has_command()) return boost::optional<command>(nullptr);
else {
boost::optional<command> comm(command_feed.front()); //command_feed is declared as a std::queue<command>
command_feed.pop();
return comm;
}
}
The problem is, these commands could be megabytes in size, under the right circumstances, and need to parse pretty quickly. My thought was that I could optimize the transferal to a move like so:
boost::optional<command> get_command() {
if (!has_command()) return boost::optional<command>(nullptr);
else {
boost::optional<command> comm(std::move(command_feed.front())); //command_feed is declared as a std::queue<command>
command_feed.pop();
return comm;
}
}
And it seems to work for this specific case, but can this be used as a general purpose solution to any properly maintained RAII object, or should I be doing something else?
Since it is impossible for pop() to return a value in such a way as to be both efficient and correct, it is more sensible for it to return no value at all and to require clients to use front() to inspect the value at the front of the queue.
C++ Queue Library - pop() Function The C++ function std::queue::pop() removes front element of the queue and reduces size of the queue by one. This member function effectively calls the pop_front member function of the underlying container.
"pop() removes the object from the underlying container, hence calls its destructor (if any)".
Yes, this is perfectly safe:
std::queue<T> q; // add stuff... T top = std::move(q.front()); q.pop();
pop()
doesn't have any preconditions on the first element in the q
having a specified state, and since you're not subsequently using q.front()
you don't have to deal with that object being invalidated any more.
Sounds like a good idea to do!
It depends on what the move constructor for your type does. If it leaves the original object in a state that can safely be destroyed, then all is well. If not, then you may be in trouble. Note that the comments about preconditions and valid states are about constraints on types defined in the standard library. Types that you define do not have those constraints, except to the extent that they use types from the standard library. So look at your move constructor to sort out what you can and can't do with a moved-from object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With