programing tip

std :: cout 조작 후 상태 복원

itbloger 2020. 9. 5. 09:26
반응형

std :: cout 조작 후 상태 복원


다음과 같은 코드가 있다고 가정합니다.

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::boolalphastd::noboolalpha..)?

감사.


필요 #include <iostream>하거나 #include <ios>필요할 때 :

std::ios_base::fmtflags f( cout.flags() );

//Your code here...

cout.flags( f );

함수의 시작과 끝에 넣거나 RAII 와 함께 사용하는 방법에 대한 이 답변 을 확인할 수 있습니다 .


부스트 IO 스트림 주립 보호기는 당신이 필요로 정확히 보인다. :-)

코드 스 니펫을 기반으로 한 예 :

void printHex(std::ostream& x) {
    boost::io::ios_flags_saver ifs(x);
    x << std::hex << 123;
}

여기에 제시된 답변은의 전체 상태를 복원하지 않습니다 std::cout. 예를 들어 std::setfill은를 호출 한 후에도 "고정" .flags()됩니다. 더 나은 해결책은 다음을 사용하는 것입니다 .copyfmt.

std::ios oldState(nullptr);
oldState.copyfmt(std::cout);

std::cout
    << std::hex
    << std::setw(8)
    << std::setfill('0')
    << 0xDECEA5ED
    << std::endl;

std::cout.copyfmt(oldState);

std::cout
    << std::setw(15)
    << std::left
    << "case closed"
    << std::endl;

다음을 인쇄합니다.

case closed

보다는 :

case closed0000

이 답변의 예제 코드를 사용하여 RAII 클래스를 만들었습니다. 이 기술의 큰 장점은 iostream에 플래그를 설정하는 함수에서 여러 반환 경로가있는 경우에 발생합니다. 어떤 반환 경로를 사용하든 소멸자는 항상 호출되고 플래그는 항상 재설정됩니다. 함수가 반환 될 때 플래그를 복원하는 것을 잊을 가능성이 없습니다.

class IosFlagSaver {
public:
    explicit IosFlagSaver(std::ostream& _ios):
        ios(_ios),
        f(_ios.flags()) {
    }
    ~IosFlagSaver() {
        ios.flags(f);
    }

    IosFlagSaver(const IosFlagSaver &rhs) = delete;
    IosFlagSaver& operator= (const IosFlagSaver& rhs) = delete;

private:
    std::ostream& ios;
    std::ios::fmtflags f;
};

그런 다음 현재 플래그 상태를 저장하고 싶을 때마다 IosFlagSaver의 로컬 인스턴스를 만들어 사용합니다. 이 인스턴스가 범위를 벗어나면 플래그 상태가 복원됩니다.

void f(int i) {
    IosFlagSaver iosfs(std::cout);

    std::cout << i << " " << std::hex << i << " ";
    if (i < 100) {
        std::cout << std::endl;
        return;
    }
    std::cout << std::oct << i << std::endl;
}

With a little bit of modification to make the output more readable :

void printHex(std::ostream& x) {
   ios::fmtflags f(x.flags());
   x << std::hex << 123 << "\n";
   x.flags(f);
}

int main() {
    std::cout << 100 << "\n"; // prints 100 base 10
    printHex(std::cout);      // prints 123 in hex
    std::cout << 73 << "\n";  // problem! prints 73 in hex..
}

You can create another wrapper around the stdout buffer:

#include <iostream>
#include <iomanip>
int main() {
    int x = 76;
    std::ostream hexcout (std::cout.rdbuf());
    hexcout << std::hex;
    std::cout << x << "\n"; // still "76"
    hexcout << x << "\n";   // "4c"
}

In a function:

void print(std::ostream& os) {
    std::ostream copy (os.rdbuf());
    copy << std::hex;
    copy << 123;
}

Of course if performance is an issue this is a bit more expensive because it's copying the entire ios object (but not the buffer) including some stuff that you're paying for but unlikely to use such as the locale.

Otherwise I feel like if you're going to use .flags() it's better to be consistent and use .setf() as well rather than the << syntax (pure question of style).

void print(std::ostream& os) {
    std::ios::fmtflags os_flags (os.flags());
    os.setf(std::ios::hex);
    os << 123;
    os.flags(os_flags);
}

As others have said you can put the above (and .precision() and .fill(), but typically not the locale and words-related stuff that is usually not going to be modified and is heavier) in a class for convenience and to make it exception-safe; the constructor should accept std::ios&.

참고URL : https://stackoverflow.com/questions/2273330/restore-the-state-of-stdcout-after-manipulating-it

반응형