एसटीडी की स्थिति को पुनर्स्थापित करें :: इसे हेरफेर करने के बाद cout


105

मान लीजिए कि मेरे पास एक कोड है:

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..)?

धन्यवाद।


मेरा मानना ​​है कि हेक्स केवल अगली पाली के ऑपरेशन के लिए रहता है। यदि आप मैनिपुलेटर्स का उपयोग करने के बजाय मैन्युअल रूप से फ़्लैग फ़्लैट बदलते हैं तो परिवर्तन केवल लगातार होता है।
बिली ओनेल

4
@ बिलियन: नहीं, मैनिपुलेटर्स का उपयोग करने का एक ही प्रभाव है कि प्रारूप झंडे को मैन्युअल रूप से बदलना। :-P
क्रिस जस्टर-यंग

3
यदि आप एक कवरटी ढूंढने के कारण नहीं हैं , तो ओस्ट्रीम फॉर्मेट (STREAM_FORMAT_STATE को पुनर्स्थापित नहीं कर रहे हैं ) , तो कवरिंग फाइंडिंग देखें : ओस्ट्रीम प्रारूप (STREAM_FORMAT_STATE को पुनर्स्थापित नहीं करना)
jww

मैंने कुछ ऐसा ही किया था - कोड समीक्षा पर मेरा प्रश्न देखें: एक मानक स्ट्रीम का उपयोग करें, और बाद में इसकी सेटिंग्स को पुनर्स्थापित करें
टॉबी स्पाईट

1
यह सवाल एक आदर्श उदाहरण है कि iostream stdio से बेहतर क्यों नहीं है। बस दो गंदे कीड़े पाए गए क्योंकि- अर्ध / / पूरी तरह से / क्या-क्या नहीं लगातार iomanip।
फुजुहि

जवाबों:


97

आपको आवश्यकता होने पर #include <iostream>या #include <ios>उसके बाद:

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

//Your code here...

cout.flags( f );

आप इन्हें अपने फ़ंक्शन के आरंभ और अंत में रख सकते हैं, या RAII के साथ इसका उपयोग कैसे करें, इस उत्तर की जाँच करें ।


5
@ क्रिसजेस्टर-यंग, वास्तव में अच्छा C ++ RAII है, विशेष रूप से इस तरह के एक मामले में!
एलेक्सिस विल्के

4
@ ऐलेक्सिस I 100% सहमत है। मेरा उत्तर देखें (Boost IO Stream State Saver)। :-)
क्रिस जस्टर-यंग

3
थिस अपवाद-सुरक्षित नहीं है।
einpoklum

2
झंडे के अलावा स्ट्रीम स्टेट के लिए और भी बहुत कुछ है।
jww

3
आप स्ट्रीम पर फ़ॉर्मेट न करके समस्या से बच सकते हैं। एक अस्थायी स्ट्रिंगस्ट्रीम चर में प्रारूप और डेटा को पुश करें, फिर प्रिंट करें
मार्क शेरेड

63

बूस्ट आईओ स्ट्रीम राज्य सेवर वास्तव में लगता है कि तुम क्या जरूरत है। :-)

आपके कोड स्निपेट के आधार पर उदाहरण:

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

1
ध्यान दें कि यहां कोई जादू नहीं है, जो ios_flags_saverमूल रूप से @ StefanKendall के उत्तर की तरह झंडे को बचाता है और सेट करता है।
einpoklum

15
@einpoklum लेकिन यह अपवाद-सुरक्षित है, अन्य उत्तर के विपरीत। ;-)
क्रिस जस्टर-यंग

2
झंडे के अलावा स्ट्रीम स्टेट के लिए और भी बहुत कुछ है।
jww

4
@jww स्ट्रीम राज्य के विभिन्न हिस्सों को बचाने के लिए IO स्ट्रीम स्टेट सेवर लाइब्रेरी के कई वर्ग हैं, जिनमें ios_flags_saverसे सिर्फ एक है।
क्रिस जस्टर-यंग

3
अगर आपको लगता है कि किसी समीक्षित, अच्छी तरह से परखी हुई लाइब्रेरी का उपयोग करने के बजाय, हर छोटी चीज़ को अपने आप में फिर से लागू करना और बनाए रखना लायक है ...
jupp0r

45

ध्यान दें कि यहां प्रस्तुत उत्तर पूर्ण स्थिति को पुनर्स्थापित नहीं करेंगे 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

यद्यपि मेरे मूल प्रश्न का उत्तर कुछ साल पहले दिया गया है, लेकिन यह उत्तर एक महान जोड़ है। :-)
अल्ट्राइन्स्टिंक्ट

2
@UltraInstinct यह एक बेहतर समाधान प्रतीत होता है , जिस स्थिति में, आप कर सकते हैं और शायद इसे इसके बजाय स्वीकृत उत्तर देना चाहिए।
अंडरस्कोर_ड

कुछ कारणों से यह अपवाद को छोड़ देता है यदि धारा के लिए अपवाद सक्षम हैं। coliru.stacked-crooked.com/a/2a4ce6f5d3d8925b
anton_rh

1
ऐसा लगता है कि std::iosयह हमेशा खराब स्थिति में है क्योंकि इसमें NULLrdbuf है। इसलिए अपवाद वाले राज्य को सेट करने से खराब स्थिति के कारण अपवाद फेंकने में सक्षम हो जाता है। समाधान: 1) के बजाय सेट के std::stringstreamसाथ कुछ वर्ग (उदाहरण के लिए) का उपयोग करें । 2) अपवादों को स्थानीय चर में अलग से सहेजें और पहले उन्हें अक्षम करें , फिर चर से अपवाद को पुनर्स्थापित करें (और फिर से उस स्थिति को पुनर्स्थापित करने के बाद ऐसा करें जिसमें अपवाद अक्षम हैं)। 3) सेट करने के लिए यह पसंद:rdbufstd::iosstate.copyfmtoldStaterdbufstd::iosstruct : std::streambuf {} sbuf; std::ios oldState(&sbuf);
anton_rh

22

मैंने इस उत्तर से उदाहरण कोड का उपयोग करके एक 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;
}

2
बहुत बढ़िया, अगर कोई फेंकता है, तो भी आपको अपनी स्ट्रीम में सही झंडे मिलते हैं।
एलेक्सिस विल्के

4
झंडे के अलावा स्ट्रीम स्टेट के लिए और भी बहुत कुछ है।
jww

1
मैं वास्तव में C ++ की कोशिश / आखिरकार अनुमति देता हूं। यह एक उत्कृष्ट उदाहरण है जहां RAII काम करता है, लेकिन अंत में सरल होता।
व्यापार-विचार फिलिप

2
यदि आपकी परियोजना कम से कम थोड़ी समझदार है, तो आपके पास बूस्ट है और इस उद्देश्य के लिए राज्य सेवर के साथ आता है ।
Jan Hudec

9

आउटपुट को अधिक पठनीय बनाने के लिए थोड़ा सा संशोधन के साथ:

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..
}

9

आप स्टडआउट बफर के आसपास एक और आवरण बना सकते हैं:

#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"
}

एक समारोह में:

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

बेशक अगर प्रदर्शन एक मुद्दा है तो यह थोड़ा अधिक महंगा है क्योंकि यह पूरी iosवस्तु (लेकिन बफर नहीं) की नकल कर रहा है, जिसमें कुछ ऐसे सामान भी शामिल हैं जिनके लिए आप भुगतान कर रहे हैं, लेकिन लोकेल जैसे उपयोग करने की संभावना नहीं है।

अन्यथा मुझे ऐसा लगता है कि यदि आप .flags()इसका उपयोग करने जा रहे हैं तो यह सुसंगत होने के .setf()साथ-साथ <<वाक्य रचना (शैली का शुद्ध प्रश्न) के बजाय बेहतर है ।

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

के रूप में अन्य लोगों ने कहा कि आप ऊपर (और रख सकते हैं .precision()और .fill()वातावरण और शब्दों से संबंधित सामान नहीं है कि आम तौर पर संशोधित किया जा करने के लिए नहीं जा रहा है और भारी है, लेकिन आम तौर पर) एक वर्ग में सुविधा के लिए है और यह अपवाद-सुरक्षित बनाने के लिए; निर्माता को स्वीकार करना चाहिए std::ios&


अच्छा बिंदु [+], लेकिन यह निश्चित std::stringstreamरूप से प्रारूप के भाग के लिए उपयोग करना याद रखता है जैसा कि मार्क शेरेड ने बताया
वुल्फ

@Wolf मुझे यकीन नहीं है कि मुझे आपकी बात मिल जाएगी। एक std::stringstream है एक std:ostreamएक द्वारा प्रस्तुत एक अतिरिक्त मध्यवर्ती बफर का उपयोग कर को छोड़कर,।
n.illillou

बेशक, दोनों आउटपुट स्वरूपण के लिए मान्य दृष्टिकोण हैं, दोनों एक स्ट्रीम ऑब्जेक्ट का परिचय देते हैं, जो आप का वर्णन करते हैं वह मेरे लिए नया है। मुझे अब पेशेवरों और विपक्ष के बारे में सोचना है। हालांकि, ज्ञानवर्धक उत्तरों के साथ एक प्रेरणादायक प्रश्न ... (मेरा मतलब है कि धारा की नकल संस्करण)
वुल्फ

1
आप एक स्ट्रीम कॉपी नहीं कर सकते, क्योंकि बफ़र्स की नकल करना अक्सर समझ में नहीं आता (उदाहरण के लिए stdout)। हालाँकि, आपके पास एक ही बफर के लिए कई स्ट्रीम ऑब्जेक्ट हो सकते हैं, जो कि यह उत्तर क्या करने का प्रस्ताव करता है। जबकि एक std:stringstreamवसीयत अपना स्वतंत्र std:stringbuf(एक std::streambufव्युत्पन्न) std::cout.rdbuf()
बनाएगी

स्पष्टीकरण के लिए धन्यवाद।
वुल्फ

0

मैं कुछ हद तक qbert220 से उत्तर को सामान्य करना चाहूंगा:

#include <ios>

class IoStreamFlagsRestorer
{
public:
    IoStreamFlagsRestorer(std::ios_base & ioStream)
        : ioStream_(ioStream)
        , flags_(ioStream_.flags())
    {
    }

    ~IoStreamFlagsRestorer()
    {
        ioStream_.flags(flags_);
    }

private:
    std::ios_base & ioStream_;
    std::ios_base::fmtflags const flags_;
};

इस इनपुट धाराओं और दूसरों के लिए भी काम करना चाहिए।

पुनश्च: मैं इसे केवल उपरोक्त उत्तर के लिए एक टिप्पणी करना पसंद करूंगा, स्टैकओवरफ्लो हालांकि मुझे लापता प्रतिष्ठा के कारण ऐसा करने की अनुमति नहीं देता है। इस प्रकार मुझे एक सरल टिप्पणी के बजाय उत्तर को अव्यवस्थित कर दें ...

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.