1. Vấn đề nó giải quyết
In thêm một dòng không luôn cần đẩy bộ đệm ngay. \n thêm ký tự xuống dòng; std::endl thêm xuống dòng rồi flush; std::flush chỉ flush. Chọn theo lúc người đọc hoặc bên nhận cần thấy dữ liệu.
2. Kiến thức cần có
Biết
std::cout, toán tử<<và chuỗi ký tự.Hiểu bộ đệm là nơi giữ dữ liệu tạm trước khi chuyển tiếp cho lớp I/O bên dưới.
3. Ý tưởng cốt lõi
Flush yêu cầu stream đồng bộ bộ đệm với nơi nhận bên dưới. Nó có thể tốn chi phí, nên buộc flush sau từng dòng có thể làm chậm việc xuất nhiều dữ liệu. Flush không tự bảo đảm dữ liệu đã được lưu bền vững trên ổ đĩa.
'\n' không tự yêu cầu flush, nhưng stream có thể được flush vì lý do khác, như unitbuf, stream được liên kết hoặc hành vi lớp I/O bên dưới. Định nghĩa endl và flush.
4. Cú pháp tối thiểu
output << "one line\n";
output << "prompt: " << std::flush;
output << "done" << std::endl;Đây là ba lựa chọn riêng cho một output stream đã khai báo: ghi dòng thường, hiện lời nhắc ngay, hoặc xuống dòng kèm flush.
5. Cách nó hoạt động
Xác định lúc cần chuyển dữ liệu ngay. Ghi tệp theo lô thường dùng
\n; lời nhắc tương tác có thể cần flush trước khi chờ phản hồi.Kiểm tra liên kết stream (tie). Mặc định
std::cinđược liên kết vớistd::cout, nên thao tác đọc thường flush đầu ra trước. Nếu bỏ liên kết bằngstd::cin.tie(nullptr), bạn phải tự bảo đảm lời nhắc đã được đẩy khi cần.std::ios::sync_with_stdio(false)thay đổi phối hợp giữa stream chuẩn C++ và stdio của C, không phải lệnh flush. Sau khi tắt, không dựa vào thứ tự xen kẽprintfvàcoutnhư khi còn đồng bộ. Nếu gọi sau khi I/O đã xảy ra, hiệu ứng phụ thuộc implementation.Kiểm tra trạng thái định dạng:
fixed,scientific, cơ số, độ chính xác và ký tự lấp đầy thường giữ nguyên tới khi đổi.std::setwđặt độ rộng, thường chỉ có hiệu lực cho một lần chèn phù hợp kế tiếp.Hàm trợ giúp dùng stream chung nên lưu và khôi phục các thuộc tính nó thay đổi, kể cả khi có exception. Sau thao tác ghi/flush quan trọng, kiểm tra trạng thái lỗi của stream thay vì coi lời gọi là bằng chứng đã ghi thành công.
6. Lỗi thường gặp
Thay mọi
\nbằngstd::endlrồi cho rằng chúng có cùng chi phí.Bỏ tie nhưng quên flush lời nhắc không có xuống dòng.
Đặt
std::fixedtrong hàm trợ giúp và vô tình đổi định dạng của các lần ghi sau.Cho rằng
std::setprecision(2)luôn là hai chữ số sau dấu thập phân; điều đó đúng vớifixed, còn định dạng mặc định dùng số chữ số có nghĩa.Cho rằng flush đồng nghĩa với ghi bền vững hoặc không thể thất bại.
7. Khi nào nên dùng
Dùng \n cho các dòng thông thường; dùng flush tại ranh giới tương tác/giao thức cần chuyển dữ liệu ngay. Nếu muốn tạo văn bản có định dạng riêng mà không ảnh hưởng stream chung, có thể dựng nó bằng std::ostringstream trước.
8. Ví dụ đơn giản
Mã mẫu C++20 giữ định dạng trên một stream riêng:
std::ostringstream output;
output << std::fixed << std::setprecision(2);
output << 3.14159 << '\n' << 2.0;Với <sstream> và <iomanip>, chuỗi thu được là 3.14\n2.00. 2.0 vẫn có hai chữ số sau dấu thập phân vì định dạng chưa được đổi. Sau đó mã mẫu ghi chuỗi ra cout và flush một lần ở cuối.
Mã mẫu hoàn chỉnh
Tệp mã nguồn
dailycppinterview/258_output-stream-buffering-and-state/main.cpp
// Real-World C++ Interviews Q258: How do C++ output buffering, '\n', std::endl, std::flush,
// stream ties, and persistent formatting state affect correctness and performance?
// Key: Writing '\n' inserts a newline without requiring a flush. std::endl inserts a newline
// and then flushes, while std::flush flushes without adding a character. Repeated forced
// flushing can dominate otherwise cheap output, so use it for an interactive or protocol
// boundary that needs visibility rather than after every line. A tied input stream may flush
// its output stream before reading, and sync_with_stdio controls coordination with C stdio
// rather than merely making output faster. Formatting such as fixed, scientific, base, fill,
// and precision generally remains on that stream until changed; width is commonly a one-use
// setting. Save and restore shared-stream state when a helper must not affect later callers. A
// flush asks buffered layers to pass data onward but does not by itself guarantee durable
// storage.
#include <iomanip>
#include <iostream>
#include <sstream>
int main() {
std::ostringstream output;
output << std::fixed << std::setprecision(2);
output << 3.14159 << '\n' << 2.0;
std::cout << output.str() << '\n';
std::cout.flush();
}
9. Điều cần nhớ
Phân biệt ba việc: thêm ký tự, chuyển bộ đệm và thay định dạng. Mỗi việc có thời điểm sử dụng và trạng thái riêng; kiểm tra lỗi nếu kết quả ghi là quan trọng.
10. Câu hỏi tự kiểm tra
Đề đầy đủ: Output buffering, '\n', std::endl, std::flush, stream tie và formatting state tồn tại lâu trong C++ ảnh hưởng correctness cùng performance thế nào?
Vì sao ví dụ in 2.00 thay vì 2? Sau cin.tie(nullptr), bạn làm gì để người dùng thấy lời nhắc trước khi nhập? Flush có bảo đảm dữ liệu đã nằm bền vững trên đĩa không?