2015-04-17 4 views
25

में स्ट्रीम को फ़्लश करने के परिणाम और पेशेवर/विपक्ष मैंने हाल ही में एक लेख पढ़ा है जिसमें कहा गया है कि std::endl का उपयोग करने के लिए बेहतर है क्योंकि endl भी स्ट्रीम को फ़्लश करता है।
लेकिन जब मैं विषय पर कुछ और जानकारी के लिए देखा मैं एक साइट जिसमें कहा गया पाया:सी ++

आप एक स्थिति आप बफरिंग से बचने के लिए है, जहां में हैं, तो आप std :: endl के बजाय का उपयोग कर सकते ' \ n '

अब यहाँ मेरे सवाल आता है: जो स्थिति में यह बफर करने के लिए लिखने के लिए बेहतर नहीं है? क्योंकि मैंने केवल उस तकनीक के फायदे देखे हैं। क्या बफर को लिखना भी सुरक्षित नहीं है? चूंकि यह हार्ड ड्राइव से छोटा है, इसलिए यह एचडी पर संग्रहीत डेटा से तेज़ी से ओवरराइट हो जाएगा (मुझे यकीन नहीं है कि यह सच है)।

+1

बफरिंग का उपयोग करते समय, यह संभव है कि आप उपयोगकर्ता से डेटा (प्रॉम्प्ट के साथ) से कुछ संवाद पूछें, और कीबोर्ड से पढ़ने से पहले पाठ मुद्रित नहीं किया गया है। कुछ परिधीय (eg.serial बंदरगाह) के मामले में, यह हो सकता है कि आप बफर को लिखते हैं, और, जब प्रोग्राम बंद हो जाता है, परिधीय भी बंद हो जाता है (और डेटा नहीं भेजा जाता है। – jcoppens

उत्तर

18

जब बफरिंग होती है तो आपको कोई गारंटी नहीं होगी कि फ़्लश होने से पहले डेटा तुरंत प्राप्त होता है । विशेष परिस्थितियों में आपको गलत आउटपुट ऑर्डरिंग और/या सूचना/डीबग डेटा का नुकसान हो सकता है, उदा।

int main() { 

    std::cout << "This text is quite nice and might as well be buffered"; 
    raise(SIGSEGV); // Oh dear.. segmentation violation 
    std::cout << std::endl; 
} 

Live Example

आउटपुट:

bash: line 7: 22235 Segmentation fault  (core dumped) ./a.out 

ऊपर प्रिंट बफरिंग के बाद से किसी भी पाठ सही उत्पादन रोका प्रदर्शित करने के लिए नहीं होगा।

अब अगर आप बस इस बफर के अंत में एक फ्लशिंग std::endl जोड़ने आप क्या मिलता है

int main() { 

    std::cout << "This text is quite nice and might as well be buffered" << std::endl; 
    raise(SIGSEGV); // Oh dear.. segmentation violation 
    std::cout << std::endl; 
} 

Live Example

आउटपुट:

This text is quite nice and might as well be buffered 
bash: line 7: 22444 Segmentation fault  (core dumped) ./a.out 

यह आउटपुट समय प्रोजेरा से पहले दिखाई दे रहा है एम समाप्ति

इस तथ्य के प्रभाव कई गुना हैं। शुद्ध रूप से सट्टा: यदि डेटा किसी सर्वर लॉग से संबंधित था, तो आपका ऐप वास्तविक लॉगिंग से पहले क्रैश हो सकता था।

10

यदि आप अपनी स्ट्रीम का लक्ष्य प्राप्त करने के बाद धारा बंद कर दिया है डेटा प्राप्त करने के बफर फ्लश करने के लिए बेहतर है।

वास्तविक जीवन उदाहरण एक एप्लिकेशन लॉग होगा, जो हमेशा से खुली धारा से लिखा जाता है ... प्रोग्राम अभी भी चल रहा है, जबकि आप इस लॉग को देखना चाहेंगे।

12

यह किसी भी परिस्थिति में बेहतर होगा जिसमें आप वास्तव में वास्तव में प्रकट होने के लिए आउटपुट दिखाना चाहते हैं।

एक साधारण उदाहरण:

#include <iostream> 
int main() { 
    std::cout << "Please enter your name: " << std::endl; 
    std::string name; 
    std::cin >> name; 
    ... 
} 

बफरिंग के साथ, कोई पाठ उपयोगकर्ता उसकी/उसके नाम टाइप करने के लिए आशा की जाती है इससे पहले कि स्क्रीन पर दिखाई देगा, तो उपयोगकर्ता उलझन में हो जाएगा। (ध्यान दें कि वास्तव में यह उदाहरण पूरी तरह से सक्षम बफरिंग के साथ चलाने के लिए वास्तव में मुश्किल या असंभव हो सकता है, क्योंकि C++ std::cout को std::cin से किसी भी इनपुट से पहले फ्लश करने के लिए विशेष उपाय कर सकता है, Why do we need to tie std::cin and std::cout? देखें। लेकिन यह केवल एक सैद्धांतिक उदाहरण है: मामले में बफरिंग पूरी तरह सक्षम है, उपयोगकर्ता को प्रॉम्प्ट नहीं दिखाई देगा।)

ऐसी स्थिति समय-समय पर हो सकती है, हालांकि यह अक्सर नहीं हो सकती है। एक और प्रक्रिया के साथ बातचीत करने के लिए एक पाइप को लिखने पर विचार करें। या यहां तक ​​कि यदि आपका प्रोग्राम लॉग फ़ाइल में लिखता है और आप समय-समय पर लॉग फ़ाइल में यह देखने के लिए देखते हैं कि यह कैसे चलता है --- बफरिंग के मामले में, आमतौर पर आप प्रोग्राम से मुद्रित आउटपुट नहीं देख पाएंगे, लेकिन फिर भी अभी तक बफर में रहता है।

यदि आपका प्रोग्राम गंभीर रूप से दुर्घटनाग्रस्त हो जाता है, तो बफर सामग्री हार्ड ड्राइव पर समाप्त नहीं हो सकती है। (मुझे लगता है कि स्ट्रीम विनाशक बफर को फ्लश करने की उम्मीद करते हैं, लेकिन एक दुर्घटना इतनी गंभीर हो सकती है कि कोई भी विनाशक नहीं कहलाएगा।)

+0

@ पीटर लेकिन क्या आपको लगता है बफर को लिखना सुरक्षित है तो एचडी पर लिखना सुरक्षित है? – TheJavaFan

+0

@TheJavaFan, "सुरक्षित" से आपका क्या मतलब है और आपको ऐसा क्यों लगता है? मुझे कोई कारण नहीं दिखता कि यह सुरक्षित क्यों हो सकता है। (अब मैं देखता हूं कि आपने पूछा यह आपके प्रश्न में भी है, लेकिन मुझे आपके प्रश्न की आखिरी वाक्य भी नहीं मिलती है।) – Petr

+0

@ पीटर मैं बस सोच रहा था कि डेटा बफर में तेजी से ओवरराइट हो जाता है तो यह एचडी – TheJavaFan

10

सबसे पहले, कुछ संशोधनवादी इतिहास।

पुराने दिनों में, जब हर कोई इस्तेमाल किया stdio.h पुस्तकालय मुझे क्या करना/हे, उस पाठ को सहभागी देखा गया था आम तौर पर लाइन बफ़र (या यहां तक ​​unbuffered) था, और पाठ कि था पूरी तरह से बफ़र नहीं किया गया। इसलिए, यदि आप स्ट्रीम में '\n' आउटपुट करते हैं, तो यह "हमेशा" सही चीज करेगा: लाइन उपयोगकर्ता उपयोगकर्ता को देख रहे थे और तुरंत देखे गए थे, और फ़ाइल को डंप करने वाली लाइनें अधिकतम प्रदर्शन के लिए buffered प्राप्त करती हैं।

दुर्भाग्यवश, यह वास्तव में हमेशा सही बात नहीं है; रनटाइम हमेशा यह अनुमान नहीं लगा सकता कि उपयोगकर्ता वास्तव में आपके प्रोग्राम के आउटपुट को कैसे देखना चाहते हैं। एक आम जाल STDOUT को पुनर्निर्देशित कर रहा है - लोगों को कंसोल में अपना प्रोग्राम चलाने और आउटपुट (इसके लाइन-बफर किए गए व्यवहार के साथ) को कंसोल में देखने के लिए उपयोग किया जाता है, और फिर किसी भी कारण (जैसे लंबे समय तक चलने वाली नौकरी) के लिए वे STDOUT को रीडायरेक्ट करने का निर्णय लेते हैं एक फ़ाइल में, और इस तथ्य से तुरंत आश्चर्यचकित हो जाता है कि आउटपुट अब लाइन-बफर नहीं है।

मैंने इस कारण से सुपरकंप्यूटर समय बर्बाद कर दिया है; आउटपुट इतना कम था कि बफरिंग ने किसी को यह बताने में सक्षम होने से रोका कि नौकरी कैसे प्रगति कर रही थी।

सी ++ की iostream लाइब्रेरी, हालांकि, इसे सही चीज करने के लिए आसान बनाने के लिए डिज़ाइन किया गया था। stdio के साथ सिंक्रनाइज़ करने के अलावा, यह इस मजाकिया "शायद लाइन-बफर्ड शायद पूरी तरह से बफर" चीज़ नहीं करता है। यह हमेशा पूर्ण बफरिंग का उपयोग करता है (बेशक जब आप अनबफर किए गए सामान को छोड़कर), और यदि आप नई लाइन पर चीजें फिसलना चाहते हैं, तो आप स्पष्ट रूप से करते हैं।

तो यदि आप किसी फ़ाइल में स्वरूपित पाठ का एक गुच्छा डंप कर रहे हैं, तो लोग आपकी लाइन ब्रेक के लिए \n लिखेंगे।

लेकिन यदि आप टेक्स्ट लिख रहे हैं तो लोग वास्तव में इसे लिखने के दौरान देखना चाहते हैं, तो आप अपनी लाइन ब्रेक के लिए std::endl का उपयोग करते हैं, और यह तुरंत प्रदर्शित हो जाता है। और यदि आप एक साथ कई लाइनें लिख रहे हैं, तो आप बेहतर भी कर सकते हैं: इंटरमीडिएट लाइन ब्रेक और std::endl के लिए अंतिम एक (या '\n' और std::flush) के लिए '\n' का उपयोग करें। यद्यपि इस सेटिंग में प्रदर्शन आमतौर पर कोई फर्क नहीं पड़ता है, इसलिए सभी लाइन ब्रेक के लिए केवल std::endl का उपयोग करना ठीक है।

+1

बस एक नोट: यहां तक ​​कि _line-buffered_ मामले में, आउटपुट हमेशा _immediately_ दिखाई नहीं देगा, यह केवल पहली नई पंक्ति के बाद दिखाई देगा। यदि आप सब कुछ एक पंक्ति में आउटपुट कर रहे हैं, तो आउटपुट प्रभावी ढंग से पूरी तरह से बफर किया जाएगा। आउटपुट वास्तव में _immediately_ दिखाई देने के लिए, आपको प्रत्येक आउटपुट के बाद 'फ्लश() 'को स्पष्ट रूप से कॉल करने की आवश्यकता है। – Petr

5

मुझे आशा है कि आपने उस साइट के लिंक को खो दिया है जिसे आपने पाया था। std::endl बफरिंग से बचें। यह बफर में जो कुछ भी है उसे फहराता है। यदि आपको बफरिंग से बचने की आवश्यकता है, तो setf(ios_base::unitbuf) का उपयोग करें। यह धारा प्रत्येक प्रविष्टि के बाद फ्लश करने के लिए सेट करता है। std::clog के लिए यह डिफ़ॉल्ट सेटिंग है। ऐसा करने का कारण यह है कि बफर में कम सामान हो रहा है, प्रोग्राम जितना क्रैश हो जाता है उतना ही महत्वपूर्ण डेटा धारा में लिखा जाएगा।

फ्लशिंग भी इंटरैक्टिव प्रोग्राम के लिए मायने रखती है: यदि आप std::cout पर एक संकेत लिखते हैं, तो यह एक अच्छा बात है यदि प्रोग्राम इनपुट के लिए प्रतीक्षा शुरू होने से पहले उस प्रॉम्प्ट पर प्रदर्शित होता है। जब आप std::cout और std::cin का उपयोग करते हैं, तब तक यह स्वचालित रूप से किया जाता है, जब तक कि आप सिंक्रनाइज़ेशन सेटिंग्स से गड़बड़ न करें।

कई प्रोग्रामर std::endl का उपयोग '\n' वर्तनी के फैंसी तरीके के रूप में करते हैं, लेकिन ऐसा नहीं है। जब भी आप इसे लिखते हैं तो आपको आउटपुट बफर को फ्लश करने की आवश्यकता नहीं होती है। ओएस और मानक पुस्तकालय अपनी नौकरियां करते हैं; वे उचित समय पर आउटपुट को समय-समय पर प्राप्त करने का ख्याल रखेंगे। आउटपुट में एक नई लाइन डालने के लिए एक सरल std::cout << '\n'; आवश्यक है, और जल्द या बाद में, जो प्रदर्शन पर दिखाई देगा। यदि आपको इसे अभी दिखाने की ज़रूरत है, आम तौर पर क्योंकि आपने समय के लिए सभी आउटपुट लिखे हैं और प्रदर्शित जानकारी को अपूर्ण नहीं छोड़ना चाहते हैं, तो आउटपुट की अंतिम पंक्ति के बाद std::endl का उपयोग करें।