अशक्त सूचक तर्क और असंभव पोस्टकंडिशन के साथ मानक अपवादों का निर्माण


9

निम्नलिखित कार्यक्रम पर विचार करें:

#include<stdexcept>
#include<iostream>

int main() {
    try {
        throw std::range_error(nullptr);
    } catch(const std::range_error&) {
        std::cout << "Caught!\n";
    }
}

GCC और Clang libstdc ++ के साथ कॉल करें std::terminateऔर संदेश के साथ कार्यक्रम को रद्द करें

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_S_construct null not valid

अपवाद के निर्माण पर libc ++ segfaults के साथ क्लैंग।

देवभूमि को देखें ।

क्या कंपाइलर मानक-अनुरूप व्यवहार कर रहे हैं? मानक के संबंधित खंड [diagnostics.range.error] (C ++ 17 N4659) का कहना है कि std::range_errorएक रचनाकार const char*अधिभार है जिसे अधिभार के ऊपर पसंद किया जाना चाहिए const std::string&। खंड भी निर्माता पर कोई पूर्व शर्त नहीं बताता है और केवल पोस्टकंडिशन बताता है

Postconditions : strcmp(what(), what_­arg) == 0

इस पोस्टकंडिशन में हमेशा what_argअशक्त व्यवहार होता है यदि एक अशक्त सूचक है, तो क्या इसका मतलब यह है कि मेरे कार्यक्रम में भी अपरिभाषित व्यवहार है और दोनों संकलक अनुरूप हैं? यदि नहीं, तो मानक में ऐसे असंभव पोस्टकंडिशन को कैसे पढ़ा जाना चाहिए?


दूसरे विचार पर, मुझे लगता है कि इसका मेरे कार्यक्रम के लिए अपरिभाषित व्यवहार का मतलब होना चाहिए, क्योंकि अगर ऐसा नहीं होता तो (वैध) संकेत शून्य-निरूपित तारों की ओर इशारा नहीं करते, जो स्पष्ट रूप से कोई मतलब नहीं है।

इसलिए, यह मानते हुए कि यह सच है, मैं इस सवाल पर अधिक ध्यान केंद्रित करना चाहता हूं कि मानक इस अपरिभाषित व्यवहार को कैसे दर्शाता है। क्या यह पोस्टकॉन्डिशन की असंभवता का पालन करता है कि कॉल में अपरिभाषित व्यवहार भी है या क्या पूर्व शर्त बस भूल गई थी?


इस सवाल से प्रेरित ।


ऐसा लगता है कि std :: range_error को संदर्भ द्वारा चीजों को संग्रहीत करने की अनुमति है, इसलिए मुझे आश्चर्य नहीं होगा। what()जब पास किया nullptrजाता है तो कॉल करने से शायद समस्या होती है।
चिपस्टर

@ किपस्टर मुझे यकीन नहीं है कि आप वास्तव में क्या मतलब है, लेकिन फिर से इस बारे में सोचने के बाद, मुझे लगता है कि यह अपरिभाषित व्यवहार होना चाहिए। मैंने अपने प्रश्न को इस पर और अधिक ध्यान केंद्रित करने के लिए संपादित किया है कि मानक शब्द कैसे अपरिभाषित व्यवहार करता है।
अखरोट

यदि nullptrपारित हो जाता है, तो मुझे लगता है कि what()मूल्य प्राप्त करने के लिए इसे किसी बिंदु पर इसे रोकना होगा। यह एक dereferencing होगा nullptr, जो कि सबसे अच्छा समस्याग्रस्त है और निश्चित रूप से क्रैश सबसे खराब हैं।
चिपस्टर

मैं सहमत हूँ, यद्यपि। यह अपरिभाषित व्यवहार होना चाहिए। हालांकि, यह बताते हुए कि मेरे कौशल से परे क्यों है, एक पर्याप्त उत्तर में डाल दिया।
चिपस्टर

मुझे लगता है कि यह इरादा है कि यह एक पूर्व शर्त है कि तर्क एक वैध सी स्ट्रिंग को इंगित करता है, क्योंकि strcmpइसका उपयोग मूल्य का वर्णन करने के लिए किया जाता है what_argसी मानक से प्रासंगिक अनुभाग वैसे भी कहते हैं, जिसे विनिर्देशन द्वारा निर्दिष्ट किया गया है <cstring>। बेशक शब्दांकन स्पष्ट हो सकता है।
एलएफ

जवाबों:


0

से दस्तावेज़ :

क्योंकि प्रतिलिपि std :: range_error को अपवादों को फेंकने की अनुमति नहीं है, यह संदेश आम तौर पर आंतरिक रूप से अलग-अलग आवंटित संदर्भ-गणना स्ट्रिंग के रूप में संग्रहीत किया जाता है। यह इसलिए भी है क्योंकि std :: string && लेने वाला कोई कंस्ट्रक्टर नहीं है: इसे कंटेंट को कॉपी करना होगा।

इससे पता चलता है कि आपको सेगफॉल्ट क्यों होता है, एपी वास्तव में इसे वास्तविक स्ट्रिंग के रूप में मानता है। सामान्य तौर पर cpp में अगर कुछ वैकल्पिक था, तो एक अतिभारित निर्माता / फ़ंक्शन होगा जो कि इसकी आवश्यकता नहीं है। तो nullptrएक ऐसे फ़ंक्शन के लिए गुजरना जो वैकल्पिक होने के लिए कुछ दस्तावेज़ नहीं करता है, अपरिभाषित व्यवहार करने जा रहा है। आमतौर पर एपीआई सी स्ट्रिंग के अपवाद के साथ संकेत नहीं लेते हैं। तो IMHO यह एक समारोह है कि एक की उम्मीद के लिए nullptr गुजर मान सुरक्षित है const char *, अपरिभाषित व्यवहार होने जा रहा है। नए एपीआई std::string_viewउन मामलों के लिए पसंद कर सकते हैं ।

अपडेट करें:

आमतौर पर C ++ API को NULL स्वीकार करने के लिए पॉइंटर ले जाना उचित है। हालाँकि C तार एक विशेष मामला है। तक std::string_view, उन्हें कुशलतापूर्वक पारित करने का कोई बेहतर तरीका नहीं था। सामान्य तौर पर एपीआई स्वीकार करने के लिए const char *, धारणा यह होनी चाहिए कि उसे वैध सी स्ट्रिंग होना चाहिए। इसका मतलब है charकि एक '\ 0' के साथ समाप्त होता है।

range_errorयह सत्यापित कर सकता है कि सूचक नहीं है, nullptrलेकिन यह मान्य नहीं हो सकता है अगर यह एक '0' के साथ समाप्त होता है। इसलिए यह बेहतर है कि कोई सत्यापन न करें।

मैं मानक में सटीक शब्द नहीं जानता, लेकिन यह पूर्व-स्थिति शायद स्वचालित रूप से मान ली गई है।


-2

यह मूल प्रश्न पर वापस जाता है क्या ndptr से std :: string बनाना ठीक है? और यह क्या करना चाहिए?

www.cplusplus.com का कहना है

यदि s एक अशक्त सूचक है, यदि n == npos, या यदि [प्रथम, अंतिम) द्वारा निर्दिष्ट सीमा मान्य नहीं है, तो यह अपरिभाषित व्यवहार का कारण बनता है।

तो कब

throw std::range_error(nullptr);

कहा जाता है कि कार्यान्वयन कुछ ऐसा बनाने की कोशिश करता है

store = std::make_shared<std::string>(nullptr);

जो अपरिभाषित है। जिसे मैं एक बग (मानक में वास्तविक शब्दों को पढ़े बिना) मानूंगा। इसके बजाय स्वतंत्र डेवलपर्स कुछ ऐसा बना सकते थे

if (what_arg)
  store = std::make_shared<std::string>(nullptr);

लेकिन फिर कैचर को nullptr के लिए जांचना what();होगा या यह वहां दुर्घटनाग्रस्त हो जाएगा। तो std::range_errorकुछ अन्य भाषाओं की तरह या तो एक खाली स्ट्रिंग या "(nullptr)" असाइन करना चाहिए।


"यह मूल प्रश्न पर वापस जाता है क्या यह एक std :: nullptr से स्ट्रिंग बनाने के लिए ठीक है?" - मुझे नहीं लगता कि यह करता है।
कोनराड रुडोल्फ

मुझे नहीं लगता कि मानक कहीं भी निर्दिष्ट करता है कि अपवाद को सहेजना है std::stringऔर std::stringनिर्माणकर्ता को अधिभार संकल्प द्वारा नहीं चुना जाना चाहिए।
अखरोट

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