Converting between STL stack and deque - c++

Is there a way to convert a C++ STL deque to a stack, and vice versa, without iterating over each element of the source manually? (I'm not sure if one of the <cast>s are usable here.)

stack is just an container adaptor, so you can just pass deque object to it to use it as a container:
std::deque<int> my_deque;
// Do something with deque here
std::stack<int> s(my_deque);
To covert in other direction, you can use constructor with the iterators:
I am not sure if you can do the direct conversion vice-versa (other than using my_deque directly). Only thing that I can think of is following:
std::deque<int> other_deck;
// Construct new stack:
std::stack<int> new_stack(other_deck);
// use std::swap
std::swap(new_stack, old_stack);
Now the other_deck should be filled with the from the old_stack.
Exchanges the contents of the container adaptor with those of other. Effectively calls using std::swap; swap(c, other.c);
Edit It seems that swap is just swapping the underlying containers, and not the container's contents, so this will not work.

Related

Fast run-time vector based std::stack. Pre-allocation and multiple pop

Is there any standard way to have the equivalent of std::vector:reserve in a std::stack<T, std::vector<T>>?
Also, is there there a standard way to implement something like pop(int count) and have it destruct elements in the correct order?
If there is no such way, short of writing a custom stack implementation, that would also answer my question.
std::stack can be used with any sequence container, and std::vector is such a container.
Then you can pass a reference to an existing container (like a pre-allocated vector) to the std::stack constructor.

How can I clear a stack in c++ efficiently?

I have a c++ stack named pages.
As I have no clear() function to clear a stack, I wrote the following code:
stack<string> pages;
//here is some operation
//now clearing the stack
while(!pages.empty())
pages.pop();
Now my question: is there a better efficient way to clear the stack?
In general you can't clear copying containers in O(1) because you need to destroy the copies. It's conceivable that a templated copying container could have a partial specialization that cleared in O(1) time that was triggered by a trait indicating the type of contained objects had a trivial destructor.
If you want to avoid loop.
pages=stack<std::string>();
or
stack<std::string>().swap(pages);
I don't think there is a more efficient way. A stack is a well defined data type, specifically designed to operate in a LIFO context, and not meant to be emptied at once.
For this you could use vector or deque (or list), which are basically the underlying containers; a stack is in fact a container adaptor. Please see this C++ Reference for more information.
If you don't have a choice, and you have to use stack, then there is nothing wrong with the way you do it. Either way, the elements have to be destroyed if they were constructed, whether you assign a new empty stack or pop all elements out or whatever.
I suggest to use a vector instead; it has the operations you need indeed:
size (or resize)
empty
push_back
pop_back
back
clear
It is just more convenient, so you can use the clear method. Not sure if using vector is really more performant; the stack operations are basically the same.
What about assigning a new empty stack to it?
pages = stack<string>();
It won't remove elements one by one and it uses move assignment so it has the potential to be quite fast.
make it into a smart pointer:
stack.reset();
stack = make_shared<stack<string>>();
What about subclassing std::stack and implementing a simple clear() method like this, accessing underlying container c ?
public:
void clear() { c.clear(); }

Possible swap map elements without copy?

I have a map<int,map<int,string>> themap
I would like to swap elements themap[1] and themap[2]. But the inside maps map<int,string> are very big so I don't want them copied. Is there way to do this or do I have to change themap to use pointers.
You can try std::map::swap for the outer map:
void swap( map& other );
Exchanges the contents of the container with those of other. Does not invoke any move, copy, or swap operations on individual elements.
themap[1].swap(themap[2]);
This won't copy, or even move, any elements in the maps. It will likely just swap ownership of the root node, just a few pointer assignments.
You can use std::swap since it has a specialization for std::map (and many other containers and library types).
std::swap(themap[1], themap[2]);
It does call std::map::swap but I think it's useful to get in the habit of using std::swap and trusting the standard committee and library implementers to do the right thing.

May I clear a priority_queue by clearing its underlying container?

The following code inherits std::priority_queue and provides clear() which calls the internal std::vector's clear()
#include<iostream>
#include<queue>
using namespace std;
template<class type>
struct mypq :public priority_queue<type> {
void clear(){
this->c.clear();
}
};
mypq<int>pq;
int main() {
for(int i=0;i<10;++i)
pq.push(i);
pq.clear();
for(int j=-5;j<0;++j)
pq.push(j);
while (!pq.empty()){
cerr<<pq.top()<<endl;
pq.pop();
}
}
When I tested it with g++, MSVC++ and clang, it produces the expected output:
-1
-2
-3
-4
-5
But I haven't seen any guarantee for this, i.e. clearing the internal vector will be the same as calling pop() when the priority_queue isn't empty. Although I know other ways to clear it such as swap or assign it using an empty priority_queue, I think if this code can work well, it would be more efficient since the allocated memory in the vector is reusable. So I wonder if this code is portable or won't always work?
But I haven't seen any guarantee for this, i.e. clearing the internal vector will be the same as calling pop() when the priority_queue isn't empty.
Because that's not the same thing. A std::priority_queue is a specifically designed container adaptor that keeps things ordered via strict weak ordering. If you don't specify the type of container the queue will have (which you don't in the example), then the default type is a std::vector.
So calling pop() on a non-empty priority queue will have the effect of removing the top element from the queue while calling clear() on the underlying container will remove all elements from the queue, not just the top most.
Although I know other ways to clear it such as swap or assign it using an empty priority_queue, I think if this code can work well, it would be more efficient since the allocated memory in the vector is reusable. So I wonder if this code is portable or won't always work?
According to the reference, the underlying c member object is protected, so accessing the way you are should be guaranteed across compilers, that is, calling this->c.clear(); should be portable (anecdotally, it works on g++ 4.2.1 on an older version of OpenBSD).
As far as efficiency is concerned, it would somewhat depend. Doing something like this->c.clear(); vs. q = priority_queue <int>(); might not be that different in terms of memory usage or complexity, though you would have to test it on the different platforms to verify. However, doing something like this->c.clear(); vs. while(!q.empty()) { q.pop(); }, would be more efficient.
In terms of memory efficiency, the pop function of the priority queue calls the underlying containers pop_back function, and neither the pop_back nor the clear affect the underlying vector's capacity, so there's not really any "savings" to be had in that way; though with this, you could resize the vector to increase/decrease capacity if you had a specific need to.
Just remember that the priority queue pop function calls the underlying containers pop_back function, and calling pop_back on an empty container is undefined behavior.
Hope that can help.
A very good question. While I can't seem to find any strict guarantee that it is a correct method, there are some reasons to think that it is.
For example, consider the docs for operator=:
Copy assignment operator. Replaces the contents with a copy of the
contents of other. Effectively calls c = other.c;. (implicitly
declared)
Since the other queue may be of a different size, this essentially means that there is no internal state that is dependent on size. Moreover, it also implies that assigning an empty queue essentially replaces the container with an empty one and does nothing else.
With that in mind, and the fact that a reasonable implementation of a priority queue would hardly need to maintain any state except for the size of the queue, I believe it can be safely assumed that clearing the underlying container is a valid way to empty the queue.

Iterating through std queue

I'm trying to use BOOST_FOREACH for iterating through the std::queue. But there isn't iterators in that class cause I have an error:
std::queue<std::string> someList;
BOOST_FOREACH(std::string temp, someList)
{
std::cout << temp;
}
>no matching function for call to begin(...)
>no type named ‘iterator’ in ‘class std::queue<std::basic_string<char> >’
I need in structure like: the first comes, the first goes away.
std::deque supports efficient insert and removal at the beginning and end of the data structure. You can do queue operations manually using push_back and pop_front.
A queue uses a deque internally by default. It's a wrapper that only exposes queue operations (hence why you can't iterate over it). I asked a similar question a while back, and the best answer gave me good insight into the real use of std::queue. One should use std::queue not because one needs a queue, but to make it clear that only queue-like operations are legal on a given data structure. It sounds like you need more freedom than that, so go with deque, list, or some other structure with O(1) insert and remove at both ends.
you can use
std::list with push_front and pop_back
std::queue is a container adaptor. It uses std::deque as the default underlying container. Access to this container isn't possible and thus isn't iteration in any way.
The best way is to use a std::deque or std::list and manage the queue behaviour yourself. Possibly provide your own wrapper around it.