Misalkan saya memiliki kode seperti ini:
void printHex(std::ostream& x){
x<<std::hex<<123;
}
..
int main(){
std::cout<<100; // prints 100 base 10
printHex(std::cout); //prints 123 in hex
std::cout<<73; //problem! prints 73 in hex..
}
Pertanyaan saya adalah apakah ada cara untuk 'mengembalikan' keadaan cout
ke semula setelah kembali dari fungsi? (Agak suka std::boolalpha
dan std::noboolalpha
..)?
Terima kasih.
Jawaban:
Anda perlu
#include <iostream>
atau#include <ios>
saat diminta:Anda dapat meletakkan ini di awal dan akhir fungsi Anda, atau lihat jawaban tentang cara menggunakan ini dengan RAII .
sumber
The Meningkatkan IO Streaming Negara Saver tampaknya apa yang Anda butuhkan. :-)
Contoh berdasarkan cuplikan kode Anda:
sumber
ios_flags_saver
pada dasarnya hanya menyimpan dan menyetel bendera seperti dalam jawaban @ StefanKendall.ios_flags_saver
hanya satu.Perhatikan bahwa jawaban yang disajikan di sini tidak akan memulihkan keadaan penuh
std::cout
. Misalnya,std::setfill
akan "tetap" bahkan setelah menelepon.flags()
. Solusi yang lebih baik adalah dengan menggunakan.copyfmt
:Akan mencetak:
daripada:
sumber
std::ios
selalu dalam keadaan buruk karena memilikiNULL
rdbuf. Jadi menyetel keadaan dengan pengecualian diaktifkan menyebabkan pengecualian melempar karena keadaan buruk. Solusi: 1) Gunakan beberapa kelas (misalnyastd::stringstream
) denganrdbuf
set, bukanstd::ios
. 2) Simpan status pengecualian secara terpisah ke variabel lokal dan nonaktifkan sebelumnyastate.copyfmt
, lalu pulihkan pengecualian dari variabel (dan lakukan ini lagi setelah memulihkan statusoldState
yang pengecualiannya dinonaktifkan). 3) Setrdbuf
kestd::ios
seperti ini:struct : std::streambuf {} sbuf; std::ios oldState(&sbuf);
Saya telah membuat kelas RAII menggunakan kode contoh dari jawaban ini. Keuntungan besar dari teknik ini datang jika Anda memiliki beberapa jalur pengembalian dari fungsi yang menyetel bendera pada iostream. Jalur pengembalian mana pun yang digunakan, destruktor akan selalu dipanggil dan bendera akan selalu disetel ulang. Tidak ada kemungkinan lupa untuk memulihkan bendera saat fungsi kembali.
Anda kemudian akan menggunakannya dengan membuat instance lokal IosFlagSaver kapan pun Anda ingin menyimpan status flag saat ini. Ketika instance ini keluar dari ruang lingkup, status bendera akan dipulihkan.
sumber
Dengan sedikit modifikasi untuk membuat keluarannya lebih mudah dibaca:
sumber
Anda dapat membuat pembungkus lain di sekitar buffer stdout:
Dalam sebuah fungsi:
Tentu saja jika kinerja menjadi masalah, ini sedikit lebih mahal karena menyalin seluruh
ios
objek (tetapi bukan buffer) termasuk beberapa hal yang Anda bayar tetapi tidak mungkin digunakan seperti lokal.Kalau tidak, saya merasa jika Anda akan menggunakannya
.flags()
lebih baik untuk konsisten dan menggunakan.setf()
juga daripada<<
sintaks (pertanyaan murni tentang gaya).Seperti yang dikatakan orang lain, Anda dapat meletakkan hal-hal di atas (dan
.precision()
dan.fill()
, tetapi biasanya bukan lokal dan hal-hal yang berhubungan dengan kata-kata yang biasanya tidak akan dimodifikasi dan lebih berat) di dalam kelas untuk kenyamanan dan membuatnya aman untuk pengecualian; konstruktor harus menerimastd::ios&
.sumber
std::stringstream
untuk bagian pemformatan seperti yang ditunjukkan Mark Sherred .std::stringstream
adalah sebuahstd:ostream
, kecuali menggunakan salah memperkenalkan buffer ekstra menengah.std:stringstream
wasiat membuat sendiristd:stringbuf
(std::streambuf
turunan), yang kemudian perlu dituangkan kestd::cout.rdbuf()
Saya ingin menggeneralisasi jawaban dari qbert220:
Ini harus berfungsi untuk aliran input dan lainnya juga.
PS: Saya ingin membuat ini hanya sebagai komentar untuk jawaban di atas, namun stackoverflow tidak mengizinkan saya melakukannya karena reputasi yang hilang. Jadi buat saya mengacaukan jawaban di sini daripada komentar sederhana ...
sumber