[C++]Why Iterating over a std::string using std::stringstream gives an exception character?

I’m trying to implement a simple format function that fills in the corresponding content based on the given format character.
I use std::stringstream to convert the given format string into a stream, and then take out the characters one by one. Then, based on the individual characters, fill in the relevant content into the output stream.
The format string is given in std::string type.

#include <iostream>
#include <sstream>
#include <string>

int main() {
    std::string fmt = "[%t]%Y-%M-%D<%H:%m:%s>:%c";
    std::stringstream s_res;
    std::stringstream s_fmt(fmt);
    while (s_fmt.good()) {
        char c = (char) s_fmt.get();
        if (c == '\0') break; // I'm not sure this stagement is necessary.
        if (c == '%') {
            switch (s_fmt.peek()) {
                case 't':
                    s_res << "Type";
                    break;
                case 'Y':
                    s_res << "Year";
                    break;
                case 'M':
                    s_res << "Month";
                    break;
                case 'D':
                    s_res << "Day";
                    break;
                case 'H':
                    s_res << "Hour";
                    break;
                case 'm':
                    s_res << "min";
                    break;
                case 's':
                    s_res << "sec";
                    break;
                case 'c':
                    s_res << "content";
                    break;
            }
            s_fmt.get();
            continue;
        }
        s_res << c;
    }
    std::cout << s_res.str();
    return 0;
}

As expected, the program should output something like this:

Expected output: [Type]Year-Month-Day<Hour:min:sec>:content

But at the end of the expected output, there is a strange character:

Actual Output:[Type]Year-Month-Day<Hour:min:sec>:contentļ£µ
========================================================^

I checked for a long time and was very troubled to find no credible explanation or concrete solution.

Is this a problem caused by encoding?

How can I solve this issue?

>Solution :

Let’s say that the last character in the stream has just been processed. There’s nothing left in the stream.

while (s_fmt.good()) {

This is perfectly fine. After all, why wouldn’t it be? Everything worked swimmingly well, up until now. The entire string has been read. Everything is still good(). The while loop continues to run:

   char c = (char) s_fmt.get();

Unfortunately, the end of the string has already been reached. This fails, and when the end of the stream has been reached get() returns

EOF and sets failbit and eofbit.

The shown code does not check that, and blindly converts the returned EOF value to a char. That’s your "strange character". And on the next iteration of the while loop, it will discover that things aren’t good() any more (the previous get() failed), and bail out. Too late.

To fix this it will be necessary to logically rearrange the sequence of events. First you get() the next character, and only then you can check if the stream is good(), and bail out otherwise. Or, alternatively, check for an explicit EOF return value, your preference.

Leave a Reply