Suponha que eu tenha um código como este:
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..
}
Minha pergunta é se há alguma maneira de 'restaurar' o estado cout
original após retornar da função? (Um pouco como std::boolalpha
e std::noboolalpha
..)?
Obrigado.
Respostas:
você precisa
#include <iostream>
ou#include <ios>
então quando necessário:Você pode colocá-los no início e no final de sua função, ou verificar esta resposta sobre como usar isso com RAII .
fonte
O protetor de estado do fluxo de IO Boost parece exatamente o que você precisa. :-)
Exemplo com base em seu snippet de código:
fonte
ios_flags_saver
basicamente apenas salva e define os sinalizadores como na resposta de @ StefanKendall.ios_flags_saver
é apenas uma.Observe que as respostas apresentadas aqui não restaurarão o estado completo de
std::cout
. Por exemplo,std::setfill
vai "grudar" mesmo depois de chamar.flags()
. A melhor solução é usar.copyfmt
:Irá imprimir:
ao invés de:
fonte
std::ios
está sempre em mau estado pois temNULL
rdbuf. Portanto, definir um estado com exceções habilitadas causa o lançamento de exceção devido ao estado incorreto. Soluções: 1) Use alguma classe (por exemplostd::stringstream
) comrdbuf
set em vez destd::ios
. 2) Salve o estado das exceções separadamente na variável local e desative-as antesstate.copyfmt
; em seguida, restaure a exceção da variável (e faça isso novamente após restaurar o estado dooldState
qual as exceções foram desativadas). 3) Definirrdbuf
astd::ios
gostar deste:struct : std::streambuf {} sbuf; std::ios oldState(&sbuf);
Criei uma classe RAII usando o código de exemplo desta resposta. A grande vantagem dessa técnica vem se você tiver vários caminhos de retorno de uma função que define sinalizadores em um iostream. Qualquer que seja o caminho de retorno usado, o destruidor sempre será chamado e os sinalizadores sempre serão redefinidos. Não há chance de esquecer de restaurar os sinalizadores quando a função retornar.
Você então o usaria criando uma instância local de IosFlagSaver sempre que quisesse salvar o estado do sinalizador atual. Quando esta instância sai do escopo, o estado do sinalizador será restaurado.
fonte
Com algumas modificações para tornar a saída mais legível:
fonte
Você pode criar outro wrapper em torno do buffer stdout:
Em uma função:
Claro, se o desempenho for um problema, isso é um pouco mais caro porque está copiando o
ios
objeto inteiro (mas não o buffer), incluindo algumas coisas que você está pagando, mas improvável de usar, como o local.Caso contrário, acho que se você for usar
.flags()
, é melhor ser consistente e usar.setf()
também do que a<<
sintaxe (pura questão de estilo).Como outros disseram, você pode colocar o acima (e
.precision()
e.fill()
, mas normalmente não o local e as coisas relacionadas a palavras que geralmente não serão modificadas e são mais pesadas) em uma classe por conveniência e para torná-la segura para exceções; o construtor deve aceitarstd::ios&
.fonte
std::stringstream
para a parte de formatação como Mark Sherred apontou .std::stringstream
é umstd:ostream
, exceto que o uso de um introduz um buffer intermediário extra.std:stringstream
criará seu próprio independentestd:stringbuf
(umstd::streambuf
derivado), que então precisa ser derramado emstd::cout.rdbuf()
Eu gostaria de generalizar a resposta de qbert220 um pouco:
Isso deve funcionar para fluxos de entrada e outros também.
PS: Eu gostaria de fazer isso simplesmente um comentário para a resposta acima, stackoverflow, entretanto, não me permite fazer isso devido à falta de reputação. Portanto, faça-me bagunçar as respostas aqui em vez de um simples comentário ...
fonte