The one model that handles the console, files, and in-memory text: insert with <<, extract with >>. Plus the modern way to format output.
C++ I/O is stream-based: a stream is a flow of characters you insert into with << or extract from with >>. The same two operators drive the console (cout/cin), files (fstream), and in-memory text (stringstream) — learn them once, use them everywhere.
std::cout is the output stream, std::cin the input. The << ("put to") and >> ("get from") operators chain, and pick the right behavior for each type automatically.
#include <iostream> std::cout << "x = " << 42 << ", ok? " << true << "\n"; // chains, type-aware int age; std::cout << "Age? "; std::cin >> age; // reads one whitespace-delimited token, parses to int std::string line; std::getline(std::cin, line); // reads a WHOLE line (including spaces) std::cerr << "error!\n"; // cerr = error stream (unbuffered, separate from cout)
>>-then-getline trap
cin >> age leaves the newline in the buffer, so a following getline reads an empty line. Fix: consume the leftover with std::cin.ignore(), or read everything with getline + parse. Also: a failed >> (bad input) puts the stream in a fail state — check if (cin >> x).Source: cppreference — std::cout / iostream.
The power of streams is uniformity: << behaves the same whether the other end is your terminal, a file, or a string in memory. They all derive from the same ostream/istream base.
std::ostream& and it works for all three. The destination is just which stream object you hand it.Open a file by constructing a stream; it closes itself when the stream object goes out of scope (RAII, Lesson 1). No manual close() needed.
#include <fstream> // write { std::ofstream out("log.txt"); // opens (creates/truncates) out << "hello\n" << 42 << "\n"; // same << as cout } // ← file flushed & closed here, automatically // read line by line std::ifstream in("log.txt"); if (!in) { /* open failed — handle it */ } std::string line; while (std::getline(in, line)) // loop ends at EOF or error process(line);
if (!in) tests for failure (open failed, bad read). while (getline(in, line)) works because getline returns the stream, which converts to false at end-of-file. This is the idiomatic read loop.Source: cppreference — file streams.
A stringstream is a stream backed by a std::string. It's the standard tool for splitting a line into fields (extract with >>) and for building a string piece by piece.
#include <sstream> // PARSE: pull typed tokens out of a line std::istringstream iss("3 14 159"); int a, b, c; iss >> a >> b >> c; // a=3, b=14, c=159 (whitespace-split + parsed) // split on a delimiter with getline std::istringstream line("a,b,c"); std::string field; while (std::getline(line, field, ',')) // field = "a", then "b", then "c" cols.push_back(field); // BUILD: assemble a string with <<, then extract it std::ostringstream oss; oss << "id=" << 7 << ";n=" << 3; std::string s = oss.str(); // "id=7;n=3"
stringstream job in C++. Keep this pattern handy — it shows up constantly in real code and interviews.Source: cppreference — std::stringstream.
Stream formatting via manipulators is verbose and stateful:
#include <iomanip> std::cout << std::fixed << std::setprecision(2) << std::setw(8) << price; // clunky & sticky
Since C++20, prefer std::format (build a string) and C++23's std::print (write it straight out) — type-safe, positional, far cleaner:
#include <print> // C++23 std::print("{:>8.2f}\n", price); // width 8, 2 decimals — no sticky state
std::format/std::print for the formatting (how they look). One performance note: for heavy console output, std::ios::sync_with_stdio(false) speeds up cin/cout.Source: cppreference — std::print (C++23).
<< and >> do on a stream?std::ofstream close its file?"3 14 159" into three ints. Reach for:<< or extract from with >>. The same model serves console, files, and in-memory strings.cin >> x vs getline?>> reads one whitespace-delimited token and parses it; getline reads a whole line (spaces included). Mixing them needs an ignore() to drop the leftover newline.std::ifstream in(path); std::string line; while (std::getline(in, line)) { ... } — the stream is truthy until EOF/error, and closes itself (RAII).stringstream for?>> or getline with a delimiter) and to build a string piece by piece, then read it with .str().bool: if (in) / if (cin >> x) is true while good, false after a failed read or EOF.std::format — division of labor?std::format/std::print handle how they're formatted. Prefer the latter over manipulators.Try: "write a CSV-line splitter with stringstream", or "why did my getline read a blank line after cin >>?" One lesson left — concurrency.