Предположим, у меня есть такой код:
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..
}
У меня вопрос: есть ли способ «восстановить» cout
исходное состояние после возврата из функции? (Что-то вроде std::boolalpha
и std::noboolalpha
..)?
Спасибо.
Ответы:
вам нужно
#include <iostream>
или#include <ios>
тогда, когда потребуется:Вы можете поместить их в начало и конец своей функции или посмотреть этот ответ о том, как использовать это с RAII .
источник
Функция Boost IO Stream State Saver кажется именно тем, что вам нужно. :-)
Пример на основе вашего фрагмента кода:
источник
ios_flags_saver
основном просто сохраняет и устанавливает флаги, как в ответе @ StefanKendall.ios_flags_saver
только один.Обратите внимание, что ответы, представленные здесь, не восстановят полное состояние
std::cout
. Например,std::setfill
будет «прилипать» даже после звонка.flags()
. Лучшее решение - использовать.copyfmt
:Напечатаем:
скорее, чем:
источник
std::ios
он всегда в плохом состоянии, потому что у него естьNULL
rdbuf. Таким образом, установка состояния с включенными исключениями вызывает выброс исключения из-за плохого состояния. Решения: 1) Используйте какой-нибудь класс (напримерstd::stringstream
) сrdbuf
set вместоstd::ios
. 2) Сохраните состояние исключений отдельно в локальной переменной и отключите их раньшеstate.copyfmt
, затем восстановите исключение из переменной (и сделайте это снова после восстановления состояния, вoldState
котором исключения отключены). 3) Установить ,rdbuf
чтобыstd::ios
это нравится:struct : std::streambuf {} sbuf; std::ios oldState(&sbuf);
Я создал класс RAII, используя пример кода из этого ответа. Большое преимущество этого метода заключается в том, что у вас есть несколько путей возврата от функции, которая устанавливает флаги в iostream. Какой бы путь возврата ни использовался, деструктор будет вызываться всегда, а флаги всегда сбрасываются. Невозможно забыть восстановить флаги, когда функция вернется.
Затем вы можете использовать его, создав локальный экземпляр IosFlagSaver всякий раз, когда вы хотите сохранить текущее состояние флага. Когда этот экземпляр выходит за пределы области видимости, состояние флага будет восстановлено.
источник
С небольшими изменениями, чтобы сделать вывод более читабельным:
источник
Вы можете создать другую оболочку вокруг буфера stdout:
В функции:
Конечно, если производительность является проблемой, это немного дороже, потому что он копирует весь
ios
объект (но не буфер), включая некоторые вещи, за которые вы платите, но вряд ли будете использовать, например, локаль.В противном случае мне кажется, что если вы собираетесь использовать
.flags()
, лучше быть последовательным и использовать,.setf()
а не<<
синтаксис (чистый вопрос стиля).Как уже говорили другие, вы можете поместить вышеперечисленное (и
.precision()
и.fill()
, но обычно не относящиеся к языку и словам вещи, которые обычно не будут изменены и тяжелее) в класс для удобства и для обеспечения безопасности исключений; конструктор должен принятьstd::ios&
.источник
std::stringstream
для части форматирования, как указал Марк Шерред .std::stringstream
- этоstd:ostream
, за исключением того, что он вводит дополнительный промежуточный буфер.std:stringstream
будет создавать свой собственный независимыйstd:stringbuf
(std::streambuf
производный), который затем нужноstd::cout.rdbuf()
Я хотел бы несколько обобщить ответ qbert220:
Это должно работать и для входных потоков, и для других.
PS: Я бы хотел сделать это просто комментарием к приведенному выше ответу, однако stackoverflow не позволяет мне сделать это из-за отсутствия репутации. Так заставьте меня загромождать здесь ответы вместо простого комментария ...
источник