স্ট্যান্ড :: সিউটের পরিস্থিতি পুনঃস্থাপনের পরে এটি পরিচালনা করে


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
@ বিলিওনিল: না, ম্যানিপুলেটরগুলি ব্যবহার করে ম্যানুয়ালি বিন্যাসের পতাকাগুলি পরিবর্তন করার মতোই প্রভাব রয়েছে। :
ক্রিস জেস্টার-ইয়াং

3
যদি আপনি এখানে ক্লাস্টি সন্ধানের কারণে অস্ট্রিমে ফর্ম্যাটটি পুনরুদ্ধার না করার কারণে হয়ে থাকেন (STREAM_FORMAT_STATE) , তবে গোপনীয়তা সন্ধান করুন: অস্ট্রিমে ফর্ম্যাটটি পুনরুদ্ধার করা হচ্ছে না (STREAM_FORMAT_STATE)
jw

আমি অনুরূপ কিছু করেছি - কোড পর্যালোচনাতে আমার প্রশ্নটি দেখুন: একটি স্ট্যান্ডার্ড স্ট্রিম ব্যবহার করুন এবং এর সেটিংস পরে পুনরুদ্ধার করুন
টবি স্পিড

1
এই প্রশ্নটি কেন স্টিডিওর চেয়ে আইস্ট্রিমে ভাল হয় না তার একটি নিখুঁত উদাহরণ। না- / আধা- / সম্পূর্ণ- / কি-অবিচ্ছিন্ন আইওমানিপের কারণে সবেমাত্র দু'টি বাজে বাগ খুঁজে পেয়েছি।
ফুজুহি

উত্তর:


97

আপনি প্রয়োজন #include <iostream>বা #include <ios>যখন প্রয়োজনীয় তারপর:

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

//Your code here...

cout.flags( f );

আপনি এগুলি আপনার ফাংশনের শুরুতে এবং শেষে রাখতে পারেন, বা কীভাবে এটি আরএআইআই ব্যবহার করবেন সে সম্পর্কে এই উত্তরটি পরীক্ষা করে দেখতে পারেন ।


5
@ ক্রিসজেস্টার-ইয়ং, আসলে ভাল সি ++ হ'ল রাই, বিশেষত এটির মতো একটি ক্ষেত্রে!
অ্যালেক্সিস উইল্ক

4
@ অ্যালেক্সিস আমি 100% সম্মত আমার উত্তর দেখুন (আইও স্ট্রিমের স্টেট সেভার বুস্ট করুন)। :-)
ক্রিস জেস্টার-ইয়াং

3
এটি ব্যতিক্রম-নিরাপদ নয়।
einpoklum

2
পতাকাগুলি ছাড়াও স্ট্রিমের স্থিতিতে আরও রয়েছে।
jwww

3
স্ট্রিমগুলিতে ফর্ম্যাটগুলি না চাপিয়ে আপনি সমস্যা এড়াতে পারেন। অস্থায়ী স্ট্রিংস্ট্রিম ভেরিয়েবলে ফর্ম্যাট এবং ডেটা পুশ করুন, তারপরে মুদ্রণ করুন
মার্ক শেরার্ড

63

বুস্ট আই স্ট্রিম রাজ্য সেভার ঠিক বলে মনে হয় আপনার যা প্রয়োজন। :-)

আপনার কোড স্নিপেটের উপর ভিত্তি করে উদাহরণ:

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

1
মনে রাখবেন যে এখানে কোনও যাদু নেই, এটি ios_flags_saverমূলত @ স্টেফানকেন্ডাল এর উত্তরের মতো পতাকাগুলি সংরক্ষণ এবং সেট করে।
einpoklum

15
@ আইনপোকলুম তবে এটি অন্যান্য জবাবের তুলনায় ব্যতিক্রম-নিরাপদ। ;-)
ক্রিস জেস্টার-ইয়াং

2
পতাকাগুলি ছাড়াও স্ট্রিমের স্থিতিতে আরও রয়েছে।
jwww

4
@jww আইও স্ট্রিম স্টেট স্টেট সেভার লাইব্রেরিতে স্ট্রিম স্টেটের বিভিন্ন অংশ সংরক্ষণ করার জন্য একাধিক ক্লাস রয়েছে, যার মধ্যে 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
@ আলট্রাআইনস্টিন্ট এটি আরও ভাল সমাধান বলে মনে হয়, এক্ষেত্রে আপনি সম্ভবত এটির পরিবর্তে গ্রহণযোগ্য উত্তরটি তৈরি করতে পারেন।
আন্ডারস্কোর_

স্ট্রিমের জন্য ব্যতিক্রম সক্ষম থাকলে কিছু কারণে এটি ব্যতিক্রম ছুঁড়ে দেয়। coliru.stacked-
ক্রুটেড.

1
মনে হয় এটি std::iosসর্বদা খারাপ অবস্থায় থাকে কারণ এটির NULLrdbuf রয়েছে। সুতরাং ব্যতিক্রম সক্ষমদের সাথে একটি রাষ্ট্র নির্ধারণ করা খারাপ অবস্থার কারণে ব্যতিক্রম ছোঁড়ার কারণ ঘটায়। সমাধান: 1) পরিবর্তে সেট std::stringstreamসহ কিছু শ্রেণি (উদাহরণস্বরূপ) ব্যবহার করুন । 2) ব্যতিক্রমগুলি পৃথকভাবে স্থানীয় ভেরিয়েবলে সংরক্ষণ করুন এবং সেগুলি পূর্বে অক্ষম করুন , তারপরে ভেরিয়েবল থেকে ব্যতিক্রম পুনরুদ্ধার করুন (এবং রাষ্ট্রটি পুনরুদ্ধার করার পরে আবার এটি করুন যা থেকে ব্যতিক্রমগুলি অক্ষম রয়েছে)। 3) এটি পছন্দ করতে সেট করুন :rdbufstd::iosstate.copyfmtoldStaterdbufstd::iosstruct : std::streambuf {} sbuf; std::ios oldState(&sbuf);
অ্যান্টন_আরহ

22

এই উত্তর থেকে উদাহরণ কোডটি ব্যবহার করে আমি একটি RAII শ্রেণি তৈরি করেছি। এই কৌশলটির বড় সুবিধাটি যদি আসে যদি আপনার কোনও ফাংশন থেকে একাধিক রিটার্ন পাথ থাকে যা একটি আইওস্ট্রিমে পতাকা সেট করে। যে কোনও রিটার্ন পাথ ব্যবহার করা হবে না কেন, সর্বনাশকারীকে সর্বদা ডাকা হবে এবং পতাকাগুলি সর্বদা পুনরায় সেট হবে। ফাংশন ফিরে এলে পতাকাগুলি পুনরুদ্ধার করতে ভুলে যাওয়ার কোনও সম্ভাবনা নেই।

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

আপনি যখনই বর্তমান পতাকাঙ্কিত অবস্থা সংরক্ষণ করতে চান তখন আপনি এটি আইওএসফ্ল্যাগ সেভারের স্থানীয় উদাহরণ তৈরি করে ব্যবহার করবেন। যখন এই উদাহরণটি সুযোগের বাইরে চলে যায়, তখন পতাকা রাষ্ট্রটি পুনরুদ্ধার করা হবে।

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
পতাকাগুলি ছাড়াও স্ট্রিমের স্থিতিতে আরও রয়েছে।
jwww

1
আমি সত্যিই সি ++ অনুমোদিত চেষ্টা / শেষ পর্যন্ত চাই। এটি একটি দুর্দান্ত উদাহরণ যেখানে আরআইআই কাজ করে তবে শেষ পর্যন্ত আরও সহজ হত।
বাণিজ্য-

2
আপনার প্রকল্পটি যদি কমপক্ষে কিছুটা বুদ্ধিমান হয় তবে আপনার বুস্ট হবে এবং এটি এই উদ্দেশ্যে রাষ্ট্র সংরক্ষণকারীদের সাথে আসে ।
জানু হুডেক

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ফর্ম্যাটিং অংশটি ব্যবহার করে স্মরণ করে যা মার্ক শেরার্ড নির্দেশ করেছেন
ওল্ফ

@ ওল্ফ আমি নিশ্চিত না যে আমি আপনার বক্তব্যটি পেয়েছি। একটি অতিরিক্ত অন্তর্বর্তী বাফার ব্যবহার না করে একটি std::stringstream হ'ল একটি std:ostream
n.caillou

অবশ্যই উভয়ই ফরম্যাটিং আউটপুটের বৈধ পন্থা, উভয়ই একটি স্ট্রিম অবজেক্টের পরিচয় দেয়, আপনি যেটি বর্ণনা করেছেন তা আমার কাছে নতুন। আমি এখন ভাল এবং কনস সম্পর্কে চিন্তা করতে হবে। যাইহোক, আলোকিত উত্তর সহ একটি অনুপ্রেরণামূলক প্রশ্ন ... (আমি স্ট্রিম অনুলিপিটির রূপটি বোঝাতে চাইছি)
ওল্ফ

1
আপনি কোনও স্ট্রিম অনুলিপি করতে পারবেন না, কারণ বাফারগুলি অনুলিপি করা প্রায়শই অর্থের সাথে আসে না (যেমন স্টডআউট)। তবে একই বাফারের জন্য আপনার বেশ কয়েকটি স্ট্রিম অবজেক্ট থাকতে পারে, যা এই উত্তরটি করার প্রস্তাব দেয়। যেখানে কোনও std:stringstreamতার নিজস্ব স্বাধীন std:stringbuf(একটি std::streambufডেরাইভেট) তৈরি করবে , যার পরে এটি poured 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_;
};

এটি ইনপুট স্ট্রিম এবং অন্যদের জন্যও কাজ করা উচিত।

পিএস: আমি উপরের উত্তরের জন্য এটি সহজভাবে মন্তব্য করতে পছন্দ করতাম, স্ট্যাকওভারফ্লো তবে সুনাম হারিয়ে যাওয়ার কারণে আমাকে এটি করতে দেয় না। সুতরাং আমাকে এখানে একটি সাধারণ মন্তব্যের পরিবর্তে উত্তরগুলি বিশৃঙ্খলা করে তোলে ...

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.