Załóżmy, że mam taki kod:
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..
}
Moje pytanie brzmi, czy istnieje sposób „przywrócenia” stanu cout
pierwotnego po powrocie z funkcji? (Trochę jak std::boolalpha
i std::noboolalpha
...)?
Dzięki.
Odpowiedzi:
musisz
#include <iostream>
lub#include <ios>
wtedy w razie potrzeby:Możesz umieścić je na początku i na końcu swojej funkcji lub sprawdzić tę odpowiedź, jak używać tego z RAII .
źródło
Doładowania IO Stream państwo oszczędzania wydaje się dokładnie to, czego potrzebują. :-)
Przykład na podstawie fragmentu kodu:
źródło
ios_flags_saver
po prostu zapisuje i ustawia flagi, jak w odpowiedzi @ StefanKendall.ios_flags_saver
jest tylko jedna.Zwróć uwagę, że przedstawione tutaj odpowiedzi nie przywrócą pełnego stanu
std::cout
. Na przykładstd::setfill
będzie się „trzymać” nawet po sprawdzeniu.flags()
. Lepszym rozwiązaniem jest użycie.copyfmt
:Wydrukuje:
zamiast:
źródło
std::ios
to, że jest zawsze w złym stanie, ponieważ maNULL
rdbuf. Zatem ustawienie stanu z włączonymi wyjątkami powoduje zgłaszanie wyjątków z powodu złego stanu. Rozwiązania: 1) Użyj jakiejś klasy (na przykładstd::stringstream
) zrdbuf
zestawem zamiaststd::ios
. 2) Zapisz stan wyjątków osobno do zmiennej lokalnej i wyłącz je wcześniejstate.copyfmt
, a następnie przywróć wyjątek ze zmiennej (i zrób to ponownie po przywróceniu stanu, zoldState
którego wyjątki są wyłączone). 3) Zestawrdbuf
dostd::ios
słuszne:struct : std::streambuf {} sbuf; std::ios oldState(&sbuf);
Utworzyłem klasę RAII, używając przykładowego kodu z tej odpowiedzi. Dużą zaletą tej techniki jest sytuacja, gdy masz wiele ścieżek powrotu z funkcji, która ustawia flagi w iostream. Niezależnie od używanej ścieżki powrotnej, destruktor będzie zawsze wywoływany, a flagi zawsze będą resetowane. Nie można zapomnieć o przywróceniu flag, gdy funkcja powróci.
Można go następnie użyć, tworząc lokalną instancję IosFlagSaver, ilekroć chcesz zapisać bieżący stan flagi. Gdy to wystąpienie znajdzie się poza zakresem, stan bandery zostanie przywrócony.
źródło
Z niewielkimi modyfikacjami, aby wynik był bardziej czytelny:
źródło
Możesz utworzyć inną otokę wokół bufora stdout:
W funkcji:
Oczywiście, jeśli problemem jest wydajność, jest to trochę droższe, ponieważ polega na kopiowaniu całego
ios
obiektu (ale nie bufora), w tym niektórych rzeczy, za które płacisz, ale prawdopodobnie nie używasz, takich jak ustawienia regionalne.W przeciwnym razie czuję, że jeśli zamierzasz używać
.flags()
, lepiej być konsekwentnym i używać.setf()
również zamiast<<
składni (czysta kwestia stylu).Jak powiedzieli inni, możesz umieścić powyższe (i
.precision()
i.fill()
, ale zwykle nie dotyczy to ustawień regionalnych i słów, które zwykle nie będą modyfikowane i są cięższe) w klasie dla wygody i aby były bezpieczne; konstruktor powinien zaakceptowaćstd::ios&
.źródło
std::stringstream
do formatowania, jak wskazał Mark Sherred .std::stringstream
jest anstd:ostream
, z wyjątkiem tego, że użycie one wprowadza dodatkowy bufor pośredni.std:stringstream
wola stworzy własną niezależnąstd:stringbuf
(std::streambuf
pochodną), którą następnie trzeba wlaćstd::cout.rdbuf()
Chciałbym nieco uogólnić odpowiedź z qbert220:
Powinno to działać również w przypadku strumieni wejściowych i innych.
PS: Chciałbym to zrobić po prostu jako komentarz do powyższej odpowiedzi, jednak stackoverflow nie pozwala mi na to z powodu braku reputacji. W ten sposób zaśmiecę tutaj odpowiedzi zamiast prostego komentarza ...
źródło