2017-09-05 7 views
7

पर अपवाद मैंने हाल ही में सीखा है कि कोई iostreams के लिए अपवादों में ऑप्ट-इन कर सकता है। आदेश में मैन्युअल रूप से जाँच करने के लिए अगर एक फ़ाइल खुला मुझे लगता है कि कोशिश की और इस व्यवहार में भाग है नहीं करने के लिए:iostreams

#include <algorithm> 
#include <iostream> 
#include <iterator> 
#include <sstream> 
#include <vector> 

void test(std::istream& is, bool exceptions) { 
    try { 
    if (exceptions) 
     is.exceptions(std::istream::failbit); 
    std::vector<int> input; 
    std::copy(std::istream_iterator<int>{is}, {}, std::back_inserter(input)); 
    for (auto x : input) { 
     std::cout << x << '\n'; 
    } 
    } 
    catch (const std::ios_base::failure& f) { 
    std::cerr << "Caught error: " << f.what() << '\n'; 
    } 
} 

int main() { 
    // Emulates file 
    std::stringstream ss("1 2 3\n4 5 6\n7 8 9\n"); 
    test(ss, true); 
} 

जब अपवाद बंद सेट कर रहे हैं यह सामान्य रूप से काम करता है। लेकिन जब मैं अपवादों का उपयोग करता हूं तो मुझे basic_ios::clear से फेंक दिया जाता है और मैं एक कारण के बारे में नहीं सोच सकता।

basic_ios::clear समारोह cppreference के अनुसार failbit सेट कर सकते हैं कि के तहत सूचीबद्ध नहीं है।

अग्रिम धन्यवाद।

संपादित करें: नीचे दिए गए उत्तर पहले से ही जवाब देते हैं कि ऐसा क्यों होता है। मेरा अतिरिक्त सवाल यह है कि इस अपवाद से कैसे बचें? मेरे दूसरे प्रयास इस पाश से std::copy को बदलने के लिए किया गया था:

for (int n; is >> n;) { 
    input.push_back(n); 
} 

एक ही अपवाद का उत्पादन किया। या यह व्यवहार भी इरादा है?

नोट: क्लैंग इस व्यवहार को नहीं दिखाता है।

+0

'basic_ios :: clear' निम्नतम स्तर की प्रविष्टि है जो Iostate सेट करता है। अन्य कार्यों में 'basic_ios :: clear' को कॉल करके विफलता/बैडबिट/eofbit सेट करें। – cpplearner

+0

@cpplearner: यह स्पष्ट करने के लिए धन्यवाद। मुझे अभी भी पता नहीं है कि उपरोक्त स्निपेट किसी भी अपवाद को क्यों फेंकता है। – sv90

उत्तर

3

जोन्सिनेटर ने आपको अपवाद का कारण दिया है, मैं केवल यह कहना चाहता हूं कि त्रुटि अपवाद से स्वतंत्र रूप से है या नहीं। वास्तव में आपका कार्य बराबर नहीं है, आप अपवाद शाखा में ऑपरेशन के बाद स्ट्रीम की जांच नहीं करते हैं। वास्तव में, एक त्रुटि चुपचाप होती है। आप एक बराबर तरह से दो कार्य लिखते हैं तो आप एक बराबर परिणाम प्राप्त होगा:

#include <iostream> 
#include <iterator> 
#include <sstream> 
#include <vector> 

void test_exception(std::istream& is) { 
    try { 
    is.exceptions(std::istream::failbit); 
    std::vector<int> input; 
    std::copy(std::istream_iterator<int>{is}, {}, std::back_inserter(input)); 
    for (auto x : input) { 
     std::cout << x << '\n'; 
    } 
    } 
    catch (const std::ios_base::failure& f) { 
    std::cout << "Caught error: " << f.what() << '\n'; 
    } 
} 

void test_error_code(std::istream& is) {  
    std::vector<int> input; 
    std::copy(std::istream_iterator<int>{is}, {}, std::back_inserter(input)); 
    if (!is.good()) { 
     std::cout << "Caught error!" << std::endl; 
     return; 
    } 
    for (auto x : input) { 
     std::cout << x << '\n'; 
    }  
} 

int main() { 
    // Emulates file 
    std::stringstream ss_error_code("1 2 3\n4 5 6\n7 8 9\n"); 
    test_error_code(ss_error_code); 

    std::stringstream ss_exception("1 2 3\n4 5 6\n7 8 9\n"); 
    test_exception(ss_exception); 
} 

उत्पादन:

पकड़ा त्रुटि!

पकड़ा त्रुटि: basic_ios :: स्पष्ट

IMHO, यह एक महान उदाहरण क्यों अपवाद परिदृश्य के विशाल बहुमत में परिणाम कोड पर बेहतर होते है और वे डिफ़ॉल्ट के रूप में इस्तेमाल किया जाना चाहिए।

+0

उत्तर के लिए धन्यवाद! एकमात्र चीज जो मुझे अभी भी समझ में नहीं आ रही है वह है कि अपवाद को पहले स्थान पर क्यों फेंक दिया गया है। मैंने सोचा कि एल्गोरिदम के साथ इटरेटर्स का उपयोग करना फ़ाइल को पढ़ने का बेवकूफ तरीका होना चाहिए। क्या आप कच्चे लूप का उपयोग करने के अलावा उन अपवादों या त्रुटि कोडों को प्राप्त करने के लिए कोड को संशोधित करने के तरीके के बारे में जानते हैं? – sv90

+0

@ user4990485 इनपुट के दौरान ईओएफ पहुंचने पर विफलता ईफिट के साथ सेट की जाएगी। तो बस अपवाद मास्क की बैडबिट सेट करें लेकिन विफलता सेट न करें और न ही eofbit। यह कोड पालन करने के लिए एक अभ्यास नहीं दिखाता है। – Oliv

+0

@ ओलिव: आपके स्पष्टीकरण के लिए धन्यवाद। अफसोस की बात है कि 'badbit' सेट नहीं किया गया है जब कोई फ़ाइल खोला नहीं जा सकता है, इसलिए मुझे मैन्युअल रूप से जांचना होगा जो मैं टालना चाहता था ... – sv90

4

जीडीबी का उपयोग करके आप देख सकते हैं कि त्रुटि तब होती है जब std::istream_iterator बढ़ता है।

#0 __GI_raise ([email protected]=6) at ../sysdeps/unix/sysv/linux/raise.c:51 
#1 0x00007ffff71d13fa in __GI_abort() at abort.c:89 
#2 0x00007ffff7ae80ad in __gnu_cxx::__verbose_terminate_handler()() from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#3 0x00007ffff7ae6066 in ??() from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#4 0x00007ffff7ae60b1 in std::terminate()() from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#5 0x00007ffff7ae62c9 in __cxa_throw() from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#6 0x00007ffff7b0eea3 in std::__throw_ios_failure(char const*)() from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#7 0x00007ffff7b4a82d in std::basic_ios<char, std::char_traits<char> >::clear(std::_Ios_Iostate)() from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#8 0x00007ffff7b4d52f in std::istream::operator>>(int&)() from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#9 0x00005555555556c2 in std::istream_iterator<int, char, std::char_traits<char>, long>::_M_read (this=0x7fffffffe230) at /usr/include/c++/6/bits/stream_iterator.h:121 
#10 0x0000555555555ac2 in std::istream_iterator<int, char, std::char_traits<char>, long>::operator++ (this=0x7fffffffe230) at /usr/include/c++/6/bits/stream_iterator.h:95 
#11 0x0000555555555a36 in std::__copy_move<false, false, std::input_iterator_tag>::__copy_m<std::istream_iterator<int, char, std::char_traits<char>, long>, std::back_insert_iterator<std::vector<int, std::allocator<int> > > > (__first=..., __last=..., __result=...) at /usr/include/c++/6/bits/stl_algobase.h:293 
#12 0x0000555555555965 in std::__copy_move_a<false, std::istream_iterator<int, char, std::char_traits<char>, long>, std::back_insert_iterator<std::vector<int, std::allocator<int> > > > (__first=..., __last=..., __result=...) at /usr/include/c++/6/bits/stl_algobase.h:386 
#13 0x00005555555557e2 in std::__copy_move_a2<false, std::istream_iterator<int, char, std::char_traits<char>, long>, std::back_insert_iterator<std::vector<int, std::allocator<int> > > > (__first=..., __last=..., __result=...) at /usr/include/c++/6/bits/stl_algobase.h:424 
#14 0x00005555555554c9 in std::copy<std::istream_iterator<int, char, std::char_traits<char>, long>, std::back_insert_iterator<std::vector<int, std::allocator<int> > > > (__first=..., __last=..., __result=...) at /usr/include/c++/6/bits/stl_algobase.h:456 
#15 0x00005555555550ed in test (is=..., exceptions=true) at sample.cpp:12 
#16 0x000055555555521c in main() at sample.cpp:25 

पाश unrolling, आप पा सकते हैं कि यह वेतन वृद्धि के लिए पिछले कॉल है कि समस्या का कारण बनता है, यानि कि std::istream_iterator::operator++ बुला जब इनपुट धारा खाली है।

स्टैक ट्रेस के करीब देख रहे हैं, अंतिम वृद्धि std :: istream :: ऑपरेटर >> स्ट्रीम खाली होने पर कोशिश कर रही है। cppreference के अनुसार, जिसके परिणामस्वरूप विफलता सेट की जा रही है क्योंकि ऑपरेशन स्ट्रीम से पूर्णांक निकालने में विफल रहा है।

संबंधित मुद्दे