No history yet

Understanding std::stack

Transcript

Beau

Alright Jo, so we've covered queues, which are like a line at a coffee shop—first person in is the first person to get their latte. And then we did priority queues, which is... like that same coffee shop, but the person who's late for a meeting gets to cut the line.

Jo

Exactly. The highest priority item comes out first, regardless of when it went in. So, keeping with that theme, what's another way you could organize things? Not a line, not by priority... what else is there?

Beau

Umm... like a pile? A pile of laundry? A stack of plates? Where you just put stuff on top and then take it off the top.

Jo

You just said the magic word. A stack. That's literally the next data structure we're talking about, and your analogy is perfect. It's called LIFO: Last-In, First-Out.

Beau

Last-In, First-Out. Right. The last plate you put on the stack is the first one you grab for dinner. Makes sense. So C++ has a 'std::pile'?

Jo

Close. `std::stack`. And just like with `std::queue`, it's an adapter. It wraps another container to provide that specific stack-like behavior.

Beau

Okay, so what are the main... moves? With a queue it was push and pop, front and back. For a stack, it's gotta be similar, right?

Jo

Very similar. You `push` to add an element to the top of the stack. You `pop` to remove the top element. But instead of `front` or `back`, you use `top` to look at the element that's, well, on top.

Beau

Okay, so there's no way to see the bottom element? Like, I can't peek at the first plate I put down without taking all the other plates off first?

Jo

Exactly. That's the whole point of the stack abstraction. It restricts you. You can only interact with the very top element. It simplifies the interface by design.

Beau

I see. It's intentionally limited. So how would that look in C++? If I wanted to make a stack of integers?

Jo

Pretty straightforward. You'd include the `<stack>` header. Then you'd declare it like `std::stack<int> myStack;`. And then you can just start using it. `myStack.push(10);`, then `myStack.push(20);`. Now, what's on top?

Beau

Twenty. Because it was the last one in. So if I called `myStack.top()`, I'd get back the value 20.

Jo

Correct. And if you called `myStack.pop()` right after that, what happens?

Beau

It removes the 20. So then if I called `myStack.top()` again, I'd get 10.

Jo

You've got it. The key thing to remember, just like with queues, is that `pop` is a `void` function. It doesn't return the element it removes. It just removes it. You have to call `top` first to get the value, and then `pop` to remove it.

Beau

Ah, that's a classic trip-up. So it's a two-step process: read, then remove. So what's... what's underneath it all? With `std::queue` you said the default was that `std::deque`, that double-ended queue thing.

Jo

Guess what? Same for `std::stack`. By default, it uses `std::deque` as its underlying container.

Beau

Really? But why? A stack only cares about one end. A deque is efficient at both ends. Seems like overkill.

Jo

It seems that way, but a deque is just a really flexible, good general-purpose choice. It offers efficient `push_back`, `pop_back`, and `back` operations, which is all `std::stack` needs to implement `push`, `pop`, and `top`. And it handles memory allocation well. You could also use `std::vector` or `std::list` if you wanted, but `deque` is the default for a reason.

Beau

So performance-wise, pushing and popping from a stack is fast? Because it's really just doing a `push_back` and `pop_back` on a deque?

Jo

Exactly. Those operations are amortized constant time, or O(1). Very efficient. Accessing `top` is also O(1). So for its intended purpose, a stack is extremely fast.

Beau

Okay, that makes a lot of sense. So beyond stacking plates, where would I actually use this? It feels more specific than a queue.

Jo

Oh, they're everywhere. Think about the 'undo' button in a text editor. Every time you type a word, it pushes that action onto a stack. When you hit 'undo', it just pops the last action off the stack and reverses it.

Beau

Whoa. Okay. That's a perfect example. Last action in is the first action to be undone.

Jo

Or even your web browser's back button. Every time you click a link, it pushes the old page onto a stack. You hit 'back', it pops the page off the stack and shows it to you. It's also fundamental to how function calls work in most programming languages—that's why it's called the 'call stack'.

Beau

The call stack! Of course. I've seen that in error messages a thousand times. 'Stack overflow'. It's... literally a stack that overflowed.

Jo

There you go. Usually from some runaway recursion that just keeps pushing function calls onto the stack until it runs out of memory. So, to recap in code, you'd have your stack, and you'd probably loop while it's not empty.

Beau

Right. Something like `while (!myStack.empty())`. Inside the loop, I'd get the top element, `int value = myStack.top();`, do something with it, and then call `myStack.pop();` to move to the next one.

Jo

That's the classic pattern for processing a whole stack. You've nailed it. It's a simple, powerful tool that you start seeing everywhere once you know what to look for.

Beau

So it's not a line, it's not a VIP line, it's just a pile. And sometimes, a pile is exactly what you need.