Show Lecture.IO as a slide show.
CS253 I/O
I/O Class Hierarchy
I/O Class Hierarchy
or, if you prefer a diagram:
┌─────┐
│ ios │
└─────┘
△
┌────────────────┴────────────────┐
┌────┴────┐ ┌────┴────┐
│ istream │ │ ostream │
└─────────┘ └─────────┘
△ △
┌──────┴───────┐ ┌──────┴───────┐
┌─────┴────┐ ┌───────┴───────┐ ┌───────┴───────┐ ┌────┴─────┐
│ ifstream │ │ istringstream │ │ ostringstream │ │ ofstream │
└──────────┘ └───────────────┘ └───────────────┘ └──────────┘
The △ indicates inheritance.
More
┌─────┐
│ ios │
└─────┘
△
┌────────────────┴────────────────┐
┌────┴────┐ ┌────┴────┐
│ istream │ │ ostream │
└─────────┘ └─────────┘
△ △
┌──────┴───────┐ ┌──────┴───────┐
┌─────┴────┐ ┌───────┴───────┐ ┌───────┴───────┐ ┌────┴─────┐
│ ifstream │ │ istringstream │ │ ostringstream │ │ ofstream │
└──────────┘ └───────────────┘ └───────────────┘ └──────────┘
Methods & Operator Overloading
┌─────┐
│ ios │
└─────┘
△
┌────────────────┴────────────────┐
┌────┴────┐ ┌────┴────┐
│ istream │ │ ostream │
└─────────┘ └─────────┘
△ △
┌──────┴───────┐ ┌──────┴───────┐
┌─────┴────┐ ┌───────┴───────┐ ┌───────┴───────┐ ┌────┴─────┐
│ ifstream │ │ istringstream │ │ ostringstream │ │ ofstream │
└──────────┘ └───────────────┘ └───────────────┘ └──────────┘
- What class defines
operator<<
?
- What class defines
operator>>
?
- What class defines
.open()
?
- What class defines
.get()
?
What Header Files Define What
strange type?
Consider the error message from this bad code:
cout.zork();
c.cc:1: error: 'std::ostream' {aka 'class std::basic_ostream<char>'} has no
member named 'zork'
basic_ostream
Why!?
w-streams
- What’s a wchar_t? It’s a wide character.
- Despite its peculiar name, wchar_t is a fundamental type,
like char or int.
- Its purpose is to hold a wide character, like ñ, ⻥, or 🐟,
that doesn’t fit into a one-byte char.
- Usually identical to int, it can hold a Unicode code point,
an integer 0…144,000+.
Not a UTF-8 byte sequence—an integer code point.
char c = 'X';
wchar_t wc = L'⻥';
cout << sizeof(c) << '\n'
<< sizeof(wc) << '\n';
1
4
basic_whatever<type>
- How would my students have implemented all this? 💖 💖 💖
- After learning about templates, however, they would implement
the templated class basic_ostream, which takes either
char or wchar_t as a template argument.
Keep it DRY!
- Same for ostream and string.
Unformatted output
We’re familiar with formatted I/O using <<
or >>
:
cout << "π ≈ " << 355/113.0 << endl;
π ≈ 3.14159
There’s also unformatted output:
cout.put('h');
cout.put('i');
char data[] = " there\nextra";
cout.write(data, 7);
hi there
Unformatted input
With unformatted input, you can read an arbitrary
number of bytes:
ifstream in("/etc/resolv.conf");
char buf[80];
in.read(buf, size(buf));
cout << "⊢";
cout.write(buf, in.gcount());
cout << "⊣";
⊢search cs.colostate edu colostate.edu
nameserver 129.82.45.181
nameserver 129.82⊣
istream::read() reads into a char buffer, which
is not '\0'
terminated.
char-based unformatted input
ifstream in("/etc/resolv.conf");
char c;
c = in.peek(); cout << "First: " << c << "\n";
c = in.get(); cout << "Again: " << c << "\n";
in.unget();
c = in.get(); cout << "Again: " << c << "\n";
c = in.get(); cout << "Second: " << c << "\n";
in.ignore(10000, '9');
while (in.get(c)) cout.put(c);
First: s
Again: s
Again: s
Second: e
.82.45.181
nameserver 129.82.103.78
nameserver 129.82.103.79
seek/tell
Diogenes
- An ostream has a put (write) pointer, an integer value that
keeps track of how far along in the output we are.
Similarly, an istream has a get (read) pointer.
p
= put (write), g
= get (read)
- You can query & change these:
ofstream out("xyz");
out.write("Hxllo there\n", 11);
out.seekp(1);
out.put('e');
out.close();
cout << ifstream("xyz").rdbuf();
Hello there
Only one
Surprisingly (well, it surprised me), an fstream
(ifstream/ofstream combination) has only a single shared
put/get pointer, and not one for input and one for output.
seek/tell methods
- tell ≡ ask a question about location
- seek ≡ change location
- g ≡ discuss the input (get) pointer
- p ≡ discuss the output (put) pointer
Misuse of .open()
ifstream and ofstream both inherited fstream::open():
const string home = getpwnam("cs253")->pw_dir;
ifstream in;
in.open(home+"/pub/ducks");
for (char c; in.get(c); )
cout << c;
Huey (red)
Dewey (blue)
Louie (green)
Why have that extra step? Just associate the filename at object construction:
const string home = getpwnam("cs253")->pw_dir;
ifstream in(home+"/pub/ducks");
for (char c; in.get(c); )
cout << c;
Huey (red)
Dewey (blue)
Louie (green)
Misuse of .eof()
- People who program by guesswork are often wrong about istream::eof().
- They think that it asks “Will the next read fail?”. It doesn’t.
- It asks “Did the previous read fail?”.
ifstream in("/etc/hostname");
string line;
while (!in.eof()) { // BAD!
getline(in, line);
cout << "Data: " << line << '\n';
}
Data: beethoven
Data:
Where did that extra line come from?
The right way to detect end-of-file
Don’t inquire in advance—just go ahead and read. It will succeed or fail:
ifstream in("/etc/hostname");
string line;
while (getline(in, line))
cout << line << '\n';
beethoven
Or, with fewer source lines and a reduced scope for line
:
ifstream in("/etc/hostname");
for (string line; getline(in, line); )
cout << line << '\n';
beethoven