45

I'd like to do the following:

std::stack <int> s;
int h = 0;
s.push(2);
h = s.pop();

Such as to have h hold the value 2. When I try my method, I get “void value not ignored as it ought to be”.

Is this not the intention of the .pop() method? What is the preferred way to do this?

PinkElephantsOnParade
  • 6,452
  • 12
  • 53
  • 91

4 Answers4

57

The standard library containers separate top() and pop(): top() returns a reference to the top element, and pop() removes the top element. (And similarly for back()/pop_back() etc.).

There's a good reason for this separation, and not have pop remove the top element and return it: One guiding principle of C++ is that you don't pay for what you don't need. A single function would have no choice but to return the element by value, which may be undesired. Separating concerns gives the user the most flexibility in how to use the data structure. (See note #3 in the original STL documentation.)

(As a curiousum, you may notice that for a concurrent container, a pop-like function is actually forced to remove and return the top value atomically, since in a concurrent context, there is no such notion as "being on top" (or "being empty" for that matter). This is one of the obvious examples of how concurrent data structures take a significant performance hit in order to provide their guarantees.)

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 10
    I'd like to add more weight to the stance that `pop()` returning a value is a bad idea. Even if `pop()` returned a value efficiently, users that didn't use the return value could still pay a price: the copy-constructor could throw an exception. We wouldn't even be able to guarantee the simple act of popping off an unused value would work! (Obviously ignoring that failure of a possibility that is a throwing destructor.) – GManNickG Aug 30 '12 at 22:39
  • 1
    @GManNickG: Good point, exception safety is always important to keep in mind! – Kerrek SB Aug 30 '12 at 22:41
  • Yes, exception safety is the primary reason for the separation. Otherwise, if `pop()` returned the value, and an exception is thrown by the copy constructor, you may not be able to guarantee that the stack is in the same state it was before calling `pop()`. By splitting the functionality across two functions you can have much stronger guarantees about exception safety. – Brian Neal Aug 31 '12 at 00:20
  • 3
    @BrianNeal, there are ways to design `pop` such that an exception caused by a copy constructor still leaves the stack in a good state. As for paying for what you don't need, there could have been an alternate method `remove` that removed the top element without returning it. – Mark Ransom Aug 31 '12 at 01:55
  • @MarkRansom this exact issue is explained in detail in Herb Sutter's _Exceptional C++_ book, item 8. – Brian Neal Aug 31 '12 at 12:58
  • Basically, if the copy constructor throws, your stack has already changed state, but the item is lost forever. – Brian Neal Aug 31 '12 at 13:01
  • How would you move the top without copying? – AturSams Jun 27 '16 at 16:24
  • @zehelvion: "move" or "remove"? The former with `std::move`, the latter with `pop`. – Kerrek SB Jun 27 '16 at 16:42
  • 3
    While this design is valid, it's shortsighted 'cuz 1)removing and returning is the standard operation in stack-based algorithms 2)the definition of "pop" is "remove and return". It would make more sense to make both a version that returns and the one that doesn't, not requiring programmers to type two operations each time or resort to a macro or a subclass every time. – ivan_pozdeev Aug 15 '18 at 15:35
  • 4
    pop is a misnomer then. It does not algorithmically pop from the stack. Reasoning for the behavior aside. – Erich Sep 25 '19 at 16:54
  • But doesn't the compiler sometimes optimizes return values to be returned as references instead? Wouldn't this solve the issue? – Michel Feinstein Sep 27 '19 at 05:19
  • @mFeinstein: No, I think you're thinking of something else. No kind of optimisation can help with the fact that if you want to remove an element from the container and still talk about that element, you need to make some sort of copy, whereas access of the existing element via `top` does not require _any_ copying. – Kerrek SB Sep 28 '19 at 00:46
6

You can use:

h = s.top();

then after that use(if you want to remove the most recent value otherwise do nothing)

 s.pop();

It works the same way!!

Marco167
  • 371
  • 3
  • 7
1

You can actually use s.top() to store the element and then pop it using

s.pop().

use

int h=s.top();
s.pop()

instead of

int h=s.pop()

You cannot directly assign s.pop() to some data type, as s.pop() removes element from stack and returns nothing.

Thomas Fritsch
  • 9,639
  • 33
  • 37
  • 49
-5

S.pop() does not return any value. Because pop() is void function. If you want to see the top of the stack then it will be S.top(). If you store this value then write value = S.top().

dkg
  • 1,775
  • 14
  • 34
  • 9
    May I ask why you are answering a 3 year old question with an answer that doesn't provide any more insight into the question than the accepted answer does? – SirGuy Nov 24 '15 at 18:19