1

Why doesn't a reference to an object of type istringstream retain its last read character position after passing it to one function after another? I'm trying to use it similar to how a Scanner object in Java works.

The goal is to create a function that loops through the characters of a string, which contains a signed decimal e.g. "-14.6", and return a signed integer out of it.

For that I use istringstream on std::string, then I pass the istringstream object to one function after another, where each function reads a specific part of the decimal.

The first function reads two chars, as white spaces, from the example string " -14.6", from the istringstream object. The problem is that the second function, which should start reading the negative sign, starts reading all over again from the beginning of the string, and the position of the istringstream object is not saved.

The code looks like this:

void read_whitespace (std::istringstream &ss);
bool read_sign (std::istringstream &ss);
std::string read_digit (std::istringstream& ss);
void convert_string(const std::string& s);

int main() {
  std::string s = "  -14.6";
  convert_string(s);
  return 0;
}

void convert_string (const std::string& s) {
  std::istringstream ss(s);
  bool sign = false; 
  // This function correctly reads the two white spaces
  read_whitespace(ss); 
  // But _here_ ss starts reading again from the beginning of s
  read_sign(ss);  
  read_digit(ss);
}

void read_whitespace (std::istringstream &ss) {
  char c;
  while (ss.get(c)) {
    if (c == ' ') {
    } else {
      break;
    }
  }
}

bool read_sign (std::istringstream &ss) {
  char c;
  while (ss.get(c)) {
    if (c == '-') {
      return false;
    } else { break; }
  } 
  return true;
}
Othman H
  • 75
  • 2
  • 9
  • The code in your example reads the entire string in `read_whitespace` and nothing in `read_sign` because EOF was reached in `read_whitespace`. – Retired Ninja Aug 11 '21 at 06:32
  • @RetiredNinja I added a break if a `char` other than whitespace is read. But still, in the next function, if I print the contents of ss `cout << ss.str()`, it shows the complete string, as if the two whitespaces weren't read already. – Othman H Aug 11 '21 at 06:36
  • 1
    If you exit the loop once something other than a space was read you've already read the `-`. You'd either need to use `ss.putback(c);` to put that character back or use `c = ss.peek()` to look ahead and know when to exit before reading the wrong character. Example: https://ideone.com/AcGpOo – Retired Ninja Aug 11 '21 at 06:38
  • 1
    `ss.str()` isn't a valid way to check what you're reading. The underlying buffer is what `str()` gives you. That's not changed by reading the data. https://en.cppreference.com/w/cpp/io/basic_stringstream/str You could use `ss.unget()` instead of `ss.putback(c)` too. – Retired Ninja Aug 11 '21 at 06:44
  • 1
    @RetiredNinja Thank you. `ss.putback(c)` solved half of the problem but then I had to do anything with the read char after each `get()` to let the buffer bypass it, e.g. printing it to cout, or get is assigned to `char c`. In the code example you printed it to cout. But I wonder if this is the most efficient way to scan a string, char by char, in c++. – Othman H Aug 11 '21 at 07:34
  • In some cases you have to go character by character. You could skip the whitespace with `ss >> std::ws;` if you wanted to https://en.cppreference.com/w/cpp/io/manip/ws but that eats more than spaces and most likely does something very similar to your function internally. – Retired Ninja Aug 11 '21 at 07:46

0 Answers0