27

I'm using a Standard iostream to get some input from a file, and I'm confused about unget() versus putback(character). It seems to me from the documentation that these functions are effectively identical, where unget() just remembers the character put in, so I'm nervous. I've always used putback(character), but character is always the last read character and I've been thinking about changing to unget(). Is putback(character) always identical to unget(), if character is always the last read character?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Puppy
  • 144,682
  • 38
  • 256
  • 465

2 Answers2

18

You can't lie with unget(). It "ungets" the last-read character. You can lie with putback(c). You can "putback" some character other than the last-read character. Sometimes putting back a character other than the last-read character can be useful.

Also, if the underlying read buffer really does have buffering capability, you can "putback" more than one character. I think ungetc() is limited to one character.

Edit
Nope. It looks like unget() can go as far back as putback().

David Hammen
  • 32,454
  • 9
  • 60
  • 108
  • Not that I'm complaining about your perfectly reasonable answer, but I don't think it actually answers the question. If I replace all my `putback(character)` calls (where `character` is guaranteed to be the last read character) with `unget()`, is the defined behaviour identical? – Puppy Jul 20 '11 at 23:24
  • 2
    It sure looks that way to me. `putback()` gives you the ability to put something back other than the last-read character. If you only use `putback(last_read_character)` the effect is the same as calling `unget()`, but without the explicit guarantee that you truly are "ungetting" the last-read character. – David Hammen Jul 20 '11 at 23:41
  • I ended up using a custom stream anyway that can put back as many characters as necessary. – Puppy Jul 21 '11 at 12:31
4

It's not the answer you probably expect, but want to introduce my reasoning. Documentation stays that the methods putback and unget call streambuf::sputbackc and streambuf::sungetc respectively. Definitions are as follow:

streambuf::sungetc

Moves the get pointer one character backwards, making the last character gotten by an input operation available once again for the next input operation.

During its operation, the function will call the protected virtual member function pbackfail if the get pointer gptr points to the same position as the beginning pointer eback.

The other one:

streambuf::sputbackc

The get pointer is moved back to point to the character right before its current position so the last character gotten, c, becomes available again as the character to be read at that position by the next input operation.

During its operation, the function calls the protected virtual member function pbackfail either if the character c doesn't match gptr()[-1] or if the get pointer gptr points to the same position as the beginning pointer eback.

When c does not match the character at that position, the default definition of pbackfail in streambuf will prepend c to be the character extracted at that position if possible, but derived classes may override this behavior.

The member function sungetc behaves in a similar way but without taking any parameter

As sputbackc calls pbackfail if character doesn't match, it means the method has to check if the values are equal. It looks like the additional check is the only overhead, but have no idea how it is solved in practise. I can imagine that if the last character is not stored in the object then it has to be reread, so you might expect it even when the characters are guaranteed to be the same.

I was a little bit concerned about situation when we call unget, but last character is not available. Would the putback put the value correctly? I doubt, but it shouldn't be the case while operating on files.

tomasz
  • 12,574
  • 4
  • 43
  • 54
  • 1
    It looks like there's more than one difference. Putback looks like it prepends? Are you sure it doesn't replace. Consider input "ABC", if you read A, then B, then putback B, prepending would insert and make the input stream "ABBC". Is this true? – Lee Louviere Aug 02 '11 at 16:11
  • 1
    @Xaade, it's up to implementation, `streambuf` does nothing by default. `stringbuf` replaces character in original string (if has write privileges), but `filebuf` replaces the character in internal buffer only, so underlying file is not affected (but also decrements get pointer, so there is no effect of inserting new character into stream). More details in spec: http://www.cplusplus.com/reference/iostream/streambuf/pbackfail/. – tomasz Aug 02 '11 at 23:03