Search code examples
c++operator-overloadinginputstreamstrchr

Using strchr to overload >>


I'm trying to overload the >> operator to read a single (created with enum Symbol {e,a,b,c,d};) Symbol:

istream & operator >> (istream & is, Symbol & sym) {
  Symbol Arr[]={e,a,b,c,d};
  char ch;
  is>>ch;
  if (strchr("eabcd",ch))
    sym=Arr[ch-'e'];
      else {
        is.unget(); 
        is.setstate(ios::failbit);
      }
  return is;
}

But this reads some trash (numbers) instead of what I was looking for, leading to a segmentation fault when trying to print it with my << overload, what am I doing wrong? Edit: Oh, and of course I did add using namespace std; at the start, same with including iostream and cstring.


Solution

  • There's a few things wrong here. First, let's fix your bracing. Just always use braces. It's very difficult to see what's lined up with what:

    istream & operator >> (istream & is, Symbol & sym) {
        Symbol Arr[]={e,a,b,c,d};
        char ch;
        is>>ch;
        if (strchr("eabcd",ch)) {
            sym=Arr[ch-'e'];
        }
        else {
            is.unget(); 
            is.setstate(ios::failbit);
        }
        return is;
    }
    

    Ok great. Now, what happens if the user inputs something like 'a'. The strchr succeeds, and then you do sym = Arr[ch - 'e']. But ch - 'e' in this case is -4. That's some totally random bit of memory somewhere, so you're getting garbage. To actually use strchr, you'd need to do something like:

    const char* options = "eabcd";
    if (const char* p = strchr(options, ch)) {
        sym = Arr[p - options];
    }
    

    But that's kind of awful. I'd suggest just using a switch:

    switch (ch) {
        case 'e': sym = e; break;
        case 'a': sym = a; break;
        ...
        default:
            is.unget();
            is.setstate(ios::failbit);
    }
    

    Also, is >> ch could fail and you're not checking that. You should:

    istream& operator>>(istream& is, Symbol& sym) {
        char ch;
        if (is >> ch) {
            switch(ch) { ... }
        }
        return is;
    }