Input, Output, and Streams
|
This section documents C++23 (ISO/IEC 14882:2024), as published by ISO/IEC JTC1/SC22/WG21 (wg21), verified against the freely available working draft N5046 (eel.is/c++draft) and cppreference.com. This content was generated with the assistance of AI and should be verified against the working draft and cppreference.com before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
The Iostreams Hierarchy
std::cin/std::cout/std::cerr are pre-constructed istream/ostream objects bound to the process’s
standard streams; every other stream type (file, string, span) plugs a different backing medium into the same
istream/ostream interface.
Formatted vs. Unformatted I/O
#include <iostream>
#include <string>
int main() {
int n;
std::cin >> n; // formatted: skips leading whitespace, parses per n's type
std::string line;
std::getline(std::cin, line); // unformatted-ish: reads a whole line verbatim, including spaces
char buffer[16];
std::cin.read(buffer, sizeof(buffer)); // fully unformatted: raw bytes, no parsing at all
std::cout.write(buffer, std::cin.gcount()); // gcount(): how many bytes the last unformatted read actually got
}
Always check a stream’s state after reading (if (std::cin >> n) or if (std::cin.fail())) — a failed
extraction leaves the target variable unspecified and the stream in a failed state that silently skips every
subsequent operation until cleared.
Manipulators and <iomanip>
#include <iostream>
#include <iomanip>
int main() {
std::cout << std::fixed << std::setprecision(2) << 3.14159 << '\n'; // 3.14
std::cout << std::hex << 255 << '\n'; // ff
std::cout << std::dec << std::setw(10) << std::setfill('*') << 42 << '\n'; // ********42
std::cout << std::boolalpha << true << '\n'; // true, not 1
}
Most manipulators (std::hex, std::fixed, std::boolalpha) are sticky — they persist until changed
again; std::setw is the notable exception, applying to only the next single insertion.
String Streams
#include <sstream>
#include <string>
#include <iostream>
int main() {
std::ostringstream out;
out << "x=" << 5 << ", y=" << 10;
std::string built = out.str();
std::cout << built << '\n';
std::istringstream in("42 3.14 hello");
int i; double d; std::string s;
in >> i >> d >> s;
std::cout << i << ' ' << d << ' ' << s << '\n';
}
Binary File I/O
#include <fstream>
#include <vector>
void writeInts(const std::vector<int>& data, const char* path) {
std::ofstream out(path, std::ios::binary);
out.write(reinterpret_cast<const char*>(data.data()), data.size() * sizeof(int));
}
std::vector<int> readInts(const char* path, std::size_t count) {
std::vector<int> data(count);
std::ifstream in(path, std::ios::binary);
in.read(reinterpret_cast<char*>(data.data()), count * sizeof(int));
return data;
}
std::ios::binary disables text-mode newline translation (relevant on Windows); always open in binary mode
when reading/writing raw bytes rather than text.
std::span Buffers (<spanstream>)
C++23’s <spanstream> streams directly over an existing, fixed, non-owning buffer (a std::span) — no
internal allocation, unlike stringstream’s owned `std::string buffer:
#include <spanstream>
#include <array>
int main() {
std::array<char, 64> buffer{};
std::ospanstream out{std::span<char>(buffer)}; // braces, not parens -- parens here would be parsed as a
// function declaration (the "most vexing parse")
out << "x=" << 5;
auto written = out.span(); // the portion of "buffer" actually written, no separate allocation
(void)written;
}
Locales
A std::locale controls culture-sensitive formatting (thousands separators, decimal points, currency symbols,
date formats) for a stream:
#include <iostream>
#include <locale>
int main() {
std::cout.imbue(std::locale("")); // the user's default OS locale, instead of the always-active "C" locale
std::cout << 1234567 << '\n'; // e.g. "1,234,567" or "1.234.567" depending on the imbued locale
}
std::locale("") depends on locale data actually being installed/configured on the host — it throws
std::runtime_error if the requested locale isn’t available, so wrap it accordingly in production code.
std::osyncstream
C++20’s std::osyncstream buffers output and flushes it as one atomic block on destruction, preventing
interleaved garbled output when multiple threads write to the same stream concurrently (see
Threads and Synchronization):
#include <syncstream>
#include <iostream>
#include <thread>
void worker(int id) {
std::osyncstream(std::cout) << "worker " << id << " done\n"; // the whole line is flushed atomically
}
std::print vs. Streams
std::print/std::println (see Strings and Text) write
formatted text more concisely than chained << operators, and — on platforms where the standard library
implements it — correctly translate encoding to a Windows console without extra setup, something std::cout
with narrow char does not always do correctly:
// streams:
std::cout << "x=" << x << ", y=" << y << '\n';
// std::print:
std::println("x={}, y={}", x, y);
this comparison itself is illustrative — std::print/std::println need <print>, which is not yet in
this environment’s libstdc++ 13 (see Getting Started); the
std::cout form and every other example on this page do compile locally.
|
See Also
-
C: Input, Output and Files — the
<stdio.h>FILE*API, still available in C++ as<cstdio>and often still the pragmatic choice.