473,385 Members | 2,069 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

std::stack vs std::deque (stacked deck?)

Hello everyone,
I decided to pick c++ back up after not really having used it much in
10 years.
Just as a point of refference, there was no standard C++ last time I
used regularly.

Anyways coming back, I've fallen in love with all the improvements in
the language such as the STL. Congrats to anyone who worked on it,
you did an excellent job.

To teach myself c++ again, I decided a good first project would be to
implement a scripting language against a MUD server/client system I
originally designed in C.

Thus far I've made what I feel is incredible headway, and thanks to
this newsgroup I've gotten over a number of humps.

To make a long story short, I'm a bit confused. I went head first,
and decided the std::deque would be an ideal structure for
implementing my scripting languages stack.

Now I've had a chance to look at the boost spirit library and numerous
others, and it looks like a structure called std::stack is the
preffered method of implementing alot of the things I've implemented.

But there's a problem and I can't quite get my head around it.
std::stack is a FILO object whereas std::deque at least as I'm using
it, can be FIFO or FILO. In my case, instructions go in via push_back
and get removed via pop_front making it effectively a FIFO object.
But std::stack has push and pop methods which operate only on the top
of the stack.

To me at least it seems more natural to push an object to the bottom
and pop it from the top, which means that instructions get executed in
the order they are added.

But it looks like I'm wrong here, as I said almost every example I can
find uses std::stack, can someone smarter than me (pretty much
everyone except the guy selling viagra), explain why the std::stack
implementation is considered superior so much so that I cannot find a
single example of a VM using std::deque?

Thanks in advance!

Feb 27 '07 #1
7 7199
On Feb 26, 8:49 pm, "DevNull" <smor...@gmail.comwrote:
Hello everyone,
I decided to pick c++ back up after not really having used it much in
10 years.
Just as a point of refference, there was no standard C++ last time I
used regularly.

Anyways coming back, I've fallen in love with all the improvements in
the language such as the STL. Congrats to anyone who worked on it,
you did an excellent job.

To teach myself c++ again, I decided a good first project would be to
implement a scripting language against a MUD server/client system I
originally designed in C.

Thus far I've made what I feel is incredible headway, and thanks to
this newsgroup I've gotten over a number of humps.

To make a long story short, I'm a bit confused. I went head first,
and decided the std::deque would be an ideal structure for
implementing my scripting languages stack.

Now I've had a chance to look at the boost spirit library and numerous
others, and it looks like a structure called std::stack is the
preffered method of implementing alot of the things I've implemented.

std::stack and std:queue are usually just specializations of
std::deque (double ended queue). They implement stacks and queues,
just like the name implies.

But there's a problem and I can't quite get my head around it.
std::stack is a FILO object whereas std::deque at least as I'm using
it, can be FIFO or FILO. In my case, instructions go in via push_back
and get removed via pop_front making it effectively a FIFO object.
But std::stack has push and pop methods which operate only on the top
of the stack.

To me at least it seems more natural to push an object to the bottom
and pop it from the top, which means that instructions get executed in
the order they are added.

If you want FIFO behavior, you want a queue. If you want LIFO (FWIW,
"FILO" is pretty rare usage), then you want a stack. If you want
both, you want a double ended queue.

std::deque support push/pop_front/back since you can work on both
ends. std::queue and std::stack only support push and pop because
there's only one end each operation applies to (the same end in the
case of a stack, opposite ends in the case of a queue). You can use a
deque as either, by using the right combination of push/pop front/back
operators, or you do both, and then a dequeue becomes more than either
a stack or a queue.

But it looks like I'm wrong here, as I said almost every example I can
find uses std::stack, can someone smarter than me (pretty much
everyone except the guy selling viagra), explain why the std::stack
implementation is considered superior so much so that I cannot find a
single example of a VM using std::deque?

Presumably because the samples want a stack (LIFO) data structure.
Also, std::stack and std::queue are a simpler to use in many cases
(although they have a number of limitations when compared to
std::deques).

Feb 27 '07 #2
DevNull wrote:
[..]
To teach myself c++ again, I decided a good first project would be to
implement a scripting language against a MUD server/client system I
originally designed in C.

Thus far I've made what I feel is incredible headway, and thanks to
this newsgroup I've gotten over a number of humps.

To make a long story short, I'm a bit confused. I went head first,
and decided the std::deque would be an ideal structure for
implementing my scripting languages stack.

Now I've had a chance to look at the boost spirit library and numerous
others, and it looks like a structure called std::stack is the
preffered method of implementing alot of the things I've implemented.
std::deque is a true container. std::stack is a container adapter.
What book are you reading that doesn't explain the difference?
But there's a problem and I can't quite get my head around it.
std::stack is a FILO object whereas std::deque at least as I'm using
it, can be FIFO or FILO. In my case, instructions go in via push_back
and get removed via pop_front making it effectively a FIFO object.
But std::stack has push and pop methods which operate only on the top
of the stack.
Well, a car can go forward or backward as the driver wants it to.
However, when towing something on a rope, going backward does not
make much sense. In that case the car only goes forward. The rope
is the additional constraint that make a bi-directional mechanism
uni-directional. A std::deque is like a car, you can use it as
a queue and push and pop from either end, or you can limit yourself
and only use one end of it (the end or the beginning). Then it
loses its bi-directionality. That's what std::stack does. It
essentially _hides_ the push_front and pop_front stuff, even if
it's available in the underlying container.
To me at least it seems more natural to push an object to the bottom
and pop it from the top, which means that instructions get executed in
the order they are added.
But that's not a stack model...
But it looks like I'm wrong here, as I said almost every example I can
find uses std::stack, can someone smarter than me (pretty much
everyone except the guy selling viagra), explain why the std::stack
implementation is considered superior so much so that I cannot find a
single example of a VM using std::deque?
Nothing is superior to anything. You can organize your std::stack to
use std::deque as the underlying container. Get a decent book and
read a bit about those things.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Feb 27 '07 #3
On 27 Feb, 03:29, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:

<..>
Well, a car can go forward or backward as the driver wants it to.
However, when towing something on a rope, going backward does not
make much sense.
Hmm. I prefer the following analogy. Suppose you have a guy sitting at
a table. Now you keep feeding this guy stuff.

Important warning: BTW Its useful when performing this experiment to
use food which can be identified after it has passed through the guys
guts. For this sweetcorn is quite suitable, peas, beetroot, that sort
of thing. If you dont do this you could be wasting a lot of time
sifting the results...

Now the experiment works because its not possible for the guy to keep
eating for ever. At some point stuff has to come out..
>From which end it comes out first you can tell if the guy is acting
like a queue or a stack.

regards
Andy Little
Feb 27 '07 #4
On Feb 26, 8:56 pm, "kwikius" <a...@servocomm.freeserve.co.ukwrote:
On 27 Feb, 03:29, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:

<..>
Well, a car can go forward or backward as the driver wants it to.
However, when towing something on a rope, going backward does not
make much sense.

Hmm. I prefer the following analogy. Suppose you have a guy sitting at
a table. Now you keep feeding this guy stuff.

Important warning: BTW Its useful when performing this experiment to
use food which can be identified after it has passed through the guys
guts. For this sweetcorn is quite suitable, peas, beetroot, that sort
of thing. If you dont do this you could be wasting a lot of time
sifting the results...

Now the experiment works because its not possible for the guy to keep
eating for ever. At some point stuff has to come out..
From which end it comes out first you can tell if the guy is acting

like a queue or a stack.

regards
Andy Little
The analogies are getting a bit silly. I guess in a nutshell I'm
asking a theory question that I haven't seen covered anywhere, in any
of the docs I've read.
Why is a stack implementation LIFO used instead of FIFO which appears
on the surface to make more sense.

So I created a simple test problem, using a normal source file, and
general scoping rules I wrote a simple parser.

Turns out both implementations are acceptable in a simplistic VM at
first. However, a LIFO stack gives you scoping for free!

Look at how this simple script code breaks down.

a = 1;
b = 2;
c = a + b;
print("A + B + C =", a+b+c);

Now if you have a LIFO stack, you get VM code that looks like this
(assuming exec is called automatically)

push(assign, a, 1);
pop();
push(assign, b, 1);
pop();
push(add, a,b,result);
pop();
push(assign,c,result);
pop();
push(add,a,b,result);
pop();
push(add,c,result,result);
pop();
push(funcPrint, "A + B + C ",result);
pop();
Now lets look at this example in a FIFO stack.
push(assign,a,1);
push(assign,b,2);
push(add,a,b,result);
push(assign,c,result);
push(add,a,b,result);
push(add,c,result,result);
push(funcPrint,"A + B + C",result);
pop();
pop();
pop();
pop();
pop();
pop();
pop();

As you can see scoping becomes much harder in a FIFO stack since we
have to keep pushing the result to the bottom and continue execution.
Compare this to a LIFO where scope becomes essentially an automatic
function.

Anyways I think I've managed to answer my own question on this, thanks
for the info and setting me straight on std::stack being LIFO.

When it comes down to it though I wonder if there is/was any
performance gains to using stack vs a deque in a LIFO manner, or if
it's just syntactic sugar.

Regards,
Feb 27 '07 #5
On Feb 27, 9:49 am, "DevNull" <smor...@gmail.comwrote:
But it looks like I'm wrong here, as I said almost every example I can
find uses std::stack, can someone smarter than me (pretty much
everyone except the guy selling viagra), explain why the std::stack
implementation is considered superior so much so that I cannot find a
single example of a VM using std::deque?
Sounds like you are storing the code that is being executed in the
deque, i.e. using it as an internal representation of the program
code. This is fine, sort of... (see below). The stack is used to store
program state which is a slightly different thing.

Sounds like you have the two different things a little confused?

You don't say what the characteristics are of the scripting language,
but if it features local variables, function calls or anything like
that then a stack is the structure used to determine what values these
name have in scope at that time (this gets potentially a lot more
complex if your language has closures).

The reason why I say the deque is sort of OK for storing the program
is that it is awkward to use with any language that offers complex
control flow (or even any control flow, like if statements, loops and
function calls). You'll find a more complex structure will be easier
to work with in that case. Using it as an intermediate to queue the
next instructions (e.g. if you have some sort of operation
interleaving going on to simulate multiple threads in the script
language) is probably a good choice.
K

Feb 27 '07 #6
On Feb 26, 10:57 pm, "DevNull" <smor...@gmail.comwrote:
On Feb 26, 8:56 pm, "kwikius" <a...@servocomm.freeserve.co.ukwrote:
The analogies are getting a bit silly. I guess in a nutshell I'm
asking a theory question that I haven't seen covered anywhere, in any
of the docs I've read.
Why is a stack implementation LIFO used instead of FIFO which appears
on the surface to make more sense.

I think you're confused. A stack *is* LIFO by definition. That's
what a stack is. If a data structure is not LIFO, it's not a stack.
A queue, again by definition, is FIFO. Questioning why a stack has
been implemented LIFO rather than FIFO is flatly nonsensical.

There are many applications for both stacks and queues, but they're
not usually interchangeable. A double ended queue is a generalization
of both queues and stacks.

Feb 27 '07 #7
On 27 Feb, 04:57, "DevNull" <smor...@gmail.comwrote:
The analogies are getting a bit silly.
Well.. since comp.lang.c++ isnt moderated, and comp.lang.c++.moderated
takes itself way too serious, I like to try to raise the tone with
some bawdy humour from time to time :-)

Obviously though... I failed this time :-(

<...>
So I created a simple test problem, using a normal source file, and
general scoping rules I wrote a simple parser.
<...>

Looks fun :-)
When it comes down to it though I wonder if there is/was any
performance gains to using stack vs a deque in a LIFO manner, or if
it's just syntactic sugar.
Basically yes. Except you can theoretically replace the default
container template param with e.g your own "model" of stack etc
without changing the source code.

In which case you would then only need to provide the operations
defined for stack, without having to provide the whole interface for
more versatile containers. Thats the theory, though I generally just
stick with what I'm given...

regards
Andy Little

Feb 27 '07 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Dan Trowbridge | last post by:
He everyone, I just getting started with .NET and I am having a porting problem. I get and error in code that lookes like this (really stripped down but you get the idea)... class dt {...
1
by: bartek | last post by:
Hi, I'm sorry for asking such a simple question. I just would like to know what's the standard-defined behaviour when doing a push_back() on a std::deque. TIA, b
7
by: Dan Trowbridge | last post by:
He everyone, I am just getting started with .NET and I am having a porting problem. I get and error in code that lookssomething like this (really stripped down but you get the idea)... class...
8
by: Gernot Frisch | last post by:
std::deque<intd; d.push_front(13); int* p13 = &d.begin(); d.push_front(1); d.push_back(2); Can I be safe, that p13 points to 13? I mean, unless I erase the 13, of course.
2
by: bb | last post by:
Hi, Is there any specific reason why std::deque's pop_front & pop_back does not return the removed object? It could return the removed object by value (possibly atomically?) Cheers.
29
by: NvrBst | last post by:
I've read a bit online seeing that two writes are not safe, which I understand, but would 1 thread push()'ing and 1 thread pop()'ing be thread-safe? Basically my situation is the follows: ...
3
by: Peng Yu | last post by:
Hi, I don't understand why rbegin() -rend() gives a negative number. Since rbegin() + 1 gives the one before the last element, I think rbegin() - rend() should give a positive number. ...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.