क्या नए मानक संस्करणों के साथ C ++ में कभी भी मौन व्यवहार में बदलाव आया है?


104

(मैं बात साबित करने के लिए एक उदाहरण या दो की तलाश कर रहा हूं, सूची नहीं।)

क्या कभी ऐसा हुआ है कि C ++ मानक (जैसे 98 से 11, 11 से 14 आदि) में बदलाव ने मौजूदा, सुव्यवस्थित, परिभाषित-व्यवहार उपयोगकर्ता कोड के व्यवहार को बदल दिया - चुपचाप? नए मानक संस्करण के साथ संकलन करते समय कोई चेतावनी या त्रुटियों के साथ?

टिप्पणियाँ:

  • मैं मानकों-अनिवार्य व्यवहार के बारे में पूछ रहा हूं, कार्यान्वयनकर्ता / संकलक लेखक विकल्पों के बारे में नहीं।
  • कम ने कोड से वंचित किया, बेहतर (इस प्रश्न के उत्तर के रूप में)।
  • मुझे संस्करण पहचान जैसे कोड से मतलब नहीं है #if __cplusplus >= 201103L
  • मेमोरी मॉडल से जुड़े उत्तर ठीक हैं।

टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
शमूएल एलवाई

3
मुझे समझ नहीं आ रहा है कि यह सवाल क्यों बंद है। " क्या कभी नए मानक संस्करणों के साथ C ++ में मौन व्यवहार में बदलाव आया है? " पूरी तरह से ध्यान केंद्रित किया गया लगता है और सवाल का शरीर इससे दूर नहीं लगता है।
टेड लिंगमो

मेरे दिमाग में, सबसे बड़ा मौन ब्रेकिंग चेंज है, जो नया रूप है auto। C ++ 11 से पहले, auto x = ...;एक की घोषणा की int। के बाद, यह घोषणा करता है कि जो कुछ भी ...है।
रेमंड चेन

@RaymondChen: यह परिवर्तन केवल तभी मौन है जब आप अंतर्निहित int को परिभाषित कर रहे थे, लेकिन स्पष्ट रूप से थे- autoटाइप वेरिएबल्स कह रहे थे । मुझे लगता है कि आप शायद एक तरफ दुनिया में उन लोगों की संख्या की गिनती कर सकते हैं जो उस तरह के कोड को लिखेंगे, सिवाय
ओफ़्फ़ुस्केटेड

सच है, इसीलिए उन्होंने इसे चुना। लेकिन यह शब्दार्थ में एक बड़ा बदलाव था।
रेमंड चेन

जवाबों:


113

की वापसी प्रकार string::dataसे परिवर्तन const char*करने के लिए char*17 C ++ में यही निश्चित रूप से एक फर्क कर सकता है

void func(char* data)
{
    cout << data << " is not const\n";
}

void func(const char* data)
{
    cout << data << " is const\n";
}

int main()
{
    string s = "xyz";
    func(s.data());
}

थोड़ा संघर्ष हुआ लेकिन यह कानूनी कार्यक्रम अपने उत्पादन को C ++ 14 से C ++ 17 में बदल देगा।


7
ओह, मुझे भी एहसास नहीं था कि std::stringC ++ 17 के लिए परिवर्तन थे । यदि कुछ भी हो, तो मुझे लगता है कि C ++ 11 परिवर्तन किसी भी तरह से मौन व्यवहार परिवर्तन का कारण हो सकते हैं। +1।
ईनपोकलम

9
वंचित या नहीं, यह एक अच्छी तरह से गठित कोड में काफी अच्छी तरह से परिवर्तन दर्शाता है।
डेविड सी। रंकिन

एक तरफ के रूप में, परिवर्तन मज़ेदार लेकिन वैध उपयोग के मामलों पर आधारित होता है जब आप एक एसटीडी :: स्ट्रिंग की सामग्री को सीटू में बदलते हैं , शायद विरासत * चार पर कार्य करते हैं। यह अब पूरी तरह से वैध है: जैसा कि एक वेक्टर के साथ, एक गारंटी है कि एक अंतर्निहित, सन्निहित सरणी है जिसे आप हेरफेर कर सकते हैं (आप हमेशा लौटे संदर्भों के माध्यम से कर सकते हैं; अब इसे और अधिक प्राकृतिक और स्पष्ट बनाया गया है)। संभावित उपयोग के मामले संपादन योग्य, निश्चित-लंबाई वाले डेटा सेट (जैसे किसी प्रकार के संदेश) हैं, जो यदि एक std :: कंटेनर पर आधारित हैं, तो STL की सेवाओं जैसे लाइफ टाइम मैनेजमेंट, कॉपीबिलिटी आदि को बनाए रखें
पीटर - Reinstate Monica

81

का जवाब इस सवाल से पता चलता है कि कैसे एक वेक्टर एक एकल का उपयोग कर आरंभ size_typeमूल्य सी ++ 03 और सी ++ 11 के बीच अलग व्यवहार हो सकता है।

std::vector<Something> s(10);

C ++ 03 डिफ़ॉल्ट प्रकार Something- तत्व का एक अस्थायी ऑब्जेक्ट बनाता है और उस अस्थायी से वेक्टर में प्रत्येक तत्व की प्रतिलिपि बनाता है।

C ++ 11 डिफ़ॉल्ट रूप से वेक्टर में प्रत्येक तत्व का निर्माण करता है।

कई (अधिकांश?) मामलों में ये परिणाम बराबर अंतिम स्थिति में होते हैं, लेकिन ऐसा कोई कारण नहीं होता है। यह Somethingडिफॉल्ट / कॉपी कंस्ट्रक्टर्स के कार्यान्वयन पर निर्भर करता है ।

देखिये यह विरोधाभासी उदाहरण :

class Something {
private:
    static int counter;

public:
    Something() : v(counter++) {
        std::cout << "default " << v << '\n';
    }

    Something(Something const & other) : v(counter++) {
        std::cout << "copy " << other.v << " to " << v << '\n';
    }

    ~Something() {
        std::cout << "dtor " << v << '\n';
    }

private:
    int v;
};

int Something::counter = 0;

सी ++ 03 डिफ़ॉल्ट-निर्माण होगा एक Somethingसाथ v == 0तो कॉपी-निर्माण से अधिक है कि एक दस। अंत में, वेक्टर में दस ऑब्जेक्ट होते हैं जिनके vमान 10 के माध्यम से 1 होते हैं, समावेशी।

C ++ 11 प्रत्येक तत्व को डिफ़ॉल्ट-निर्माण करेगा। कोई नकल नहीं की जाती है। अंत में, वेक्टर में दस ऑब्जेक्ट होते हैं जिनके vमान 0 से 9, समावेशी होते हैं।


@einpoklum मैंने हालांकि एक आकस्मिक उदाहरण जोड़ा। :)
cdhowie

3
मुझे नहीं लगता कि यह विवादित है। अलग-अलग निर्माणकर्ता अक्सर अलग-अलग wrt चीजों को कार्य करते हैं, जैसे, स्मृति आवंटन। आपने बस एक साइड इफेक्ट को दूसरे (I / O) से बदल दिया।
einpoklum

17
@ LCDhowie बिल्कुल भी नहीं है। मैं हाल ही में एक यूयूआईडी क्लास पर काम कर रहा था। डिफ़ॉल्ट निर्माता ने एक यादृच्छिक UUID उत्पन्न किया। मुझे इस संभावना के बारे में कोई पता नहीं था, मैंने अभी C ++ 11 व्यवहार को माना।
जॉन

5
एक व्यापक रूप से इस्तेमाल किया जाने वाला वास्तविक विश्व उदाहरण है जहाँ यह OpenCV होता है cv::mat। डिफ़ॉल्ट कंस्ट्रक्टर नई मेमोरी आवंटित करता है, जबकि कॉपी कंस्ट्रक्टर मौजूदा मेमोरी में एक नया दृश्य बनाता है।
जपा

मैं यह नहीं कहूंगा कि एक आकस्मिक उदाहरण, यह स्पष्ट रूप से व्यवहार में अंतर को दर्शाता है।
डेविड वाटरवर्थ

51

मानक में एनेक्स सी [भिन्न] में परिवर्तन को तोड़ने की एक सूची है । इन परिवर्तनों में से कई मौन व्यवहार परिवर्तन को जन्म दे सकते हैं।

एक उदाहरण:

int f(const char*); // #1
int f(bool);        // #2

int x = f(u8"foo"); // until C++20: calls #1; since C++20: calls #2

7
@einpoklum खैर, उनमें से कम से कम एक दर्जन मौजूदा कोड के "अर्थ बदलने" या उन्हें "अलग तरीके से निष्पादित" करने के लिए कहा जाता है।
कपल

4
आप इस विशेष परिवर्तन के लिए तर्क को कैसे संक्षेप में प्रस्तुत करेंगे?
नायुकी

4
@Nayuki ने यह सुनिश्चित किया कि boolसंस्करण का उपयोग करना, प्रति से अधिक बदलाव नहीं था, अन्य रूपांतरण नियमों का सिर्फ एक साइड-इफेक्ट है। असली इरादा चरित्र एन्कोडिंग के बीच कुछ भ्रम को रोकना होगा, वास्तविक परिवर्तन जो कि u8शाब्दिक देते थे const char*लेकिन अब देते हैं const char8_t*
वामावर्तआउट

25

हर बार वे मानक पुस्तकालय में नए तरीके (और अक्सर फ़ंक्शन) जोड़ते हैं जो ऐसा होता है।

मान लीजिए कि आपके पास एक मानक पुस्तकालय प्रकार है:

struct example {
  void do_stuff() const;
};

बहुत साधारण। कुछ मानक संशोधन में, एक नई विधि या ओवरलोड या किसी भी चीज के आगे जोड़ा जाता है:

struct example {
  void do_stuff() const;
  void method(); // a new method
};

यह मौजूदा C ++ कार्यक्रमों के व्यवहार को चुपचाप बदल सकता है।

ऐसा इसलिए है क्योंकि इस तरह की विधि मौजूद होने पर C ++ के सीमित प्रतिबिंबन क्षमता का पता लगाने के लिए पर्याप्त है, और इसके आधार पर अलग-अलग कोड चलाते हैं।

template<class T, class=void>
struct detect_new_method : std::false_type {};

template<class T>
struct detect_new_method< T, std::void_t< decltype( &T::method ) > > : std::true_type {};

यह नए का पता लगाने के लिए सिर्फ एक अपेक्षाकृत सरल तरीका है method, तरीकों के असंख्य हैं।

void task( std::false_type ) {
  std::cout << "old code";
};
void task( std::true_type ) {
  std::cout << "new code";
};

int main() {
  task( detect_new_method<example>{} );
}

जब आप कक्षाओं से तरीकों को हटाते हैं तो ऐसा ही हो सकता है।

जबकि यह उदाहरण सीधे तौर पर एक पद्धति के अस्तित्व का पता लगाता है, परोक्ष रूप से होने वाली इस तरह की बात कम ही हो सकती है। एक ठोस उदाहरण के रूप में, आपके पास एक सीरियलाइज़ेशन इंजन हो सकता है जो यह तय करता है कि अगर किसी चीज को कंटेनर के रूप में क्रमबद्ध किया जा सकता है यदि वह चलने योग्य है, या यदि उसके पास डेटा-टू-रॉ-बाइट्स और एक आकार के सदस्य हैं, तो एक पसंद किया जाता है। अन्य।

मानक जाता है और .data()एक कंटेनर में एक विधि जोड़ता है , और अचानक प्रकार बदलता है जो इसे क्रमांकन के लिए उपयोग करता है।

सभी सी ++ मानक कर सकते हैं, अगर यह फ्रीज नहीं करना चाहता है, तो इस तरह का कोड बनाना है जो चुपचाप टूट जाता है दुर्लभ या किसी भी तरह अनुचित है।


3
मुझे SFINAE को बाहर करने के लिए प्रश्न को योग्य होना चाहिए क्योंकि यह वह नहीं है जो मेरा मतलब था ... लेकिन हां, यह सच है, इसलिए +1।
einpoklum

"इस तरह की बात अप्रत्यक्ष रूप से हो रही है" जिसके परिणामस्वरूप तब अपवित्र हुआ, क्योंकि यह एक वास्तविक जाल है।
इयान रिंगरोज

1
यह वास्तव में अच्छा उदाहरण है। भले ही ओपी का मतलब इसे बाहर करना था, यह संभवतः मौजूदा कोड में मौन व्यवहार परिवर्तन का कारण बनने वाली सबसे संभावित चीजों में से एक है। +1
cdhowie

1
@TedLyngmo यदि आप डिटेक्टर को ठीक नहीं कर सकते हैं, तो पता की गई चीज़ को बदल दें। टेक्सास शार्पशूटिंग!
यक - एडम नेवेरुमोंट

15

ओह लड़के ... लिंक cpplearner प्रदान की है डरावना

अन्य लोगों में, C ++ 20 ने C ++ स्ट्रक्चर्स की C- शैली संरचना की घोषणा को अस्वीकार कर दिया।

typedef struct
{
  void member_foo(); // Ill-formed since C++20
} m_struct;

यदि आपको उस तरह की संरचना लिखना सिखाया गया था (और "सी के साथ सी" सिखाने वाले लोग बिल्कुल सिखाते हैं) तो आप खराब हैं


20
जिसने भी सिखाया है कि ब्लैकबोर्ड पर 100 बार लिखना चाहिए "मुझे टाइपफेड संरचनाएं नहीं चाहिए"। आपको इसे C, imho में भी नहीं करना चाहिए। वैसे भी, यह परिवर्तन मौन नहीं है: नए मानक में, "मान्य C ++ 2017 कोड (अनाम, गैर-सी संरचना पर टाइपडिफ़ का उपयोग करते हुए) बीमार हो सकता है" और "बीमार-गठन - कार्यक्रम में वाक्यविन्यास त्रुटियां या डायग्नोस्टिक अनैतिक त्रुटियां हैं एक नैदानिक ​​जारी करने के लिए एक अनुरूप C ++ कंपाइलर की आवश्यकता होती है "
पीटर -

19
@ पीटर-रेनटामेटोनिका ठीक है, मैं हमेशा typedefअपनी संरचना करता हूं, और मैं निश्चित रूप से इस पर अपना चाक बर्बाद नहीं करने वाला हूं। यह निश्चित रूप से स्वाद का मामला है, और जब कि अत्यधिक प्रभावशाली लोग (टोरवाल्ड्स ...) हैं जो आपकी बात साझा करते हैं, तो खुद जैसे अन्य लोग इशारा करेंगे, कि प्रकारों के लिए एक नामकरण सम्मेलन की आवश्यकता है। structकीवर्ड के साथ कोड को अव्यवस्थित करने से समझ में बहुत कम आता है कि एक पूंजी पत्र ( MyClass* object = myClass_create();) संप्रेषित नहीं करेगा। अगर आप structअपने कोड में चाहते हैं तो मैं इसका सम्मान करता हूं । लेकिन मैं इसे मेरा नहीं चाहता।
सेंटास्टर -

5
उस ने कहा, जब C ++ की प्रोग्रामिंग की जाती है, तो यह structकेवल सादे-पुराने-डेटा प्रकारों के लिए उपयोग करने के लिए एक अच्छा सम्मेलन है , और classकुछ भी जिसमें सदस्य कार्य हैं। लेकिन आप सी में उस अधिवेशन का उपयोग नहीं कर सकते क्योंकि classसी में कोई नहीं है
cmaster -

1
@ पीटर- ReinstateMonica हाँ, अच्छी तरह से आप C में एक विधि वाक्य रचना को संलग्न नहीं कर सकते हैं, लेकिन इसका मतलब यह नहीं है कि C structवास्तव में COD है। जिस तरह से मैं सी कोड लिखता हूं, ज्यादातर संरचनाएं केवल एक फ़ाइल में कोड द्वारा और उन कार्यों से छुआ जाती हैं जो उनकी कक्षा का नाम रखते हैं। यह मूल रूप से सिंथेटिक चीनी के बिना OOP है। यह मुझे वास्तव में नियंत्रित करने की अनुमति देता है कि अंदर क्या परिवर्तन होता है struct, और इसके सदस्यों के बीच कौन से आक्रमणकारियों की गारंटी है। इसलिए, मेरे structsसदस्यों को उनके डेटा सदस्यों से निजी कार्य, निजी कार्यान्वयन, अपरिवर्तनीय और सार है। POD की तरह आवाज नहीं करता है, करता है?
विस्फ़ोटक -

6
जब तक वे extern "C"ब्लॉकों में निषिद्ध नहीं होते हैं , तब तक मुझे इस परिवर्तन के साथ कोई समस्या नहीं दिखाई देती है। C ++ में किसी को भी टाइप करने वाली संरचना नहीं होनी चाहिए। यह इस तथ्य से बड़ी बाधा नहीं है कि C ++ में जावा की तुलना में अलग शब्दार्थ है। जब आप एक नई प्रोग्रामिंग भाषा सीखते हैं, तो आपको कुछ नई आदतें सीखने की आवश्यकता हो सकती है।
कोड़ी ग्रे

15

यहाँ एक उदाहरण है कि C ++ 03 में 3 प्रिंट करता है लेकिन C ++ 11 में 0 है:

template<int I> struct X   { static int const c = 2; };
template<> struct X<0>     { typedef int c; };
template<class T> struct Y { static int const c = 3; };
static int const c = 4;
int main() { std::cout << (Y<X< 1>>::c >::c>::c) << '\n'; }

व्यवहार में यह परिवर्तन विशेष हैंडलिंग के कारण हुआ था >>। C ++ 11 से पहले, >>हमेशा सही शिफ्ट ऑपरेटर था। C ++ 11 के साथ, >>एक टेम्पलेट घोषणा का भी हिस्सा हो सकता है।


ठीक है, तकनीकी रूप से यह सच है, लेकिन यह कोड "अनौपचारिक रूप से अस्पष्ट" था, >>जो उस तरह के उपयोग के कारण शुरू हुआ था ।
einpoklum

11

ट्रिग्राफ गिरा दिया

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

सी ++ 17 में, ट्रिग्राफ हटा दिए गए थे। इसलिए कुछ स्रोत फ़ाइलों को नए संकलक द्वारा स्वीकार नहीं किया जाएगा, जब तक कि उन्हें पहली बार किसी अन्य भौतिक चरित्र सेट से भौतिक चरित्र सेट से अनुवादित नहीं किया जाता है, जो कि एक-से-एक स्रोत स्रोत सेट पर मैप करता है। (व्यवहार में, अधिकांश कंपाइलरों ने केवल ट्रिग्राफ की व्याख्या को वैकल्पिक बना दिया है।) यह एक सूक्ष्म व्यवहार परिवर्तन नहीं है, लेकिन एक ब्रेकिंग परिवर्तन पूर्व-स्वीकार्य स्रोत फ़ाइलों को बाहरी अनुवाद प्रक्रिया के बिना संकलित होने से रोकता है।

पर और अधिक अड़चनें char

मानक निष्पादन चरित्र सेट को भी संदर्भित करता है , जिसे कार्यान्वयन परिभाषित किया गया है, लेकिन इसमें कम से कम संपूर्ण स्रोत वर्ण सेट और कम संख्या में नियंत्रण कोड होने चाहिए।

C ++ मानक charको संभवतः-अहस्ताक्षरित अभिन्न प्रकार के रूप में परिभाषित किया गया है जो निष्पादन वर्ण सेट में प्रत्येक मान को कुशलता से दर्शा सकता है। भाषा के वकील से प्रतिनिधित्व के साथ, आप तर्क दे सकते हैं कि charकम से कम 8 बिट होना चाहिए।

यदि आपका कार्यान्वयन इसके लिए एक अहस्ताक्षरित मान का उपयोग करता है char, तो आप जानते हैं कि यह 0 से 255 तक हो सकता है, और इस प्रकार हर संभव मूल्य के भंडारण के लिए उपयुक्त है।

लेकिन अगर आपका कार्यान्वयन एक हस्ताक्षरित मूल्य का उपयोग करता है, तो इसके पास विकल्प हैं।

ज्यादातर दो-पूरक का उपयोग करेगा, charन्यूनतम -128 की सीमा 127 को देगा। यह 256 अद्वितीय मूल्य है।

लेकिन एक अन्य विकल्प था साइन + परिमाण, जहां एक बिट यह बताने के लिए आरक्षित है कि संख्या नकारात्मक है और अन्य सात बिट्स परिमाण को दर्शाते हैं। यह char-127 से 127 तक की सीमा देगा , जो केवल 255 अद्वितीय मान है। (क्योंकि आप -0 का प्रतिनिधित्व करने के लिए एक उपयोगी बिट संयोजन खो देते हैं।)

मुझे यकीन नहीं है कि समिति ने स्पष्ट रूप से इसे एक दोष के रूप में निर्दिष्ट किया है, लेकिन यह इसलिए था क्योंकि आप मानक से एक गोल-यात्रा की गारंटी देने के लिए मानक पर भरोसा नहीं कर सकते unsigned charथे charऔर वापस मूल मूल्य को संरक्षित करेंगे। (व्यवहार में, सभी कार्यान्वयनों ने किया क्योंकि वे सभी हस्ताक्षरित अभिन्न प्रकारों के लिए दो के पूरक का उपयोग करते थे।)

केवल हाल ही में (C ++ 17?) राउंड-ट्रिपिंग सुनिश्चित करने के लिए निश्चित किया गया शब्द था। यह ठीक है, अन्य सभी आवश्यकताओं के साथ char, प्रभावी रूप से charबिना स्पष्ट रूप से हस्ताक्षर किए दो के पूरक को अनिवार्य रूप से बताता है (भले ही मानक अन्य हस्ताक्षरित अभिन्न प्रकारों के लिए संकेत + परिमाण प्रतिनिधित्व की अनुमति देता है)। सभी हस्ताक्षरित अभिन्न प्रकारों के लिए दो के पूरक का उपयोग करने की आवश्यकता के लिए एक प्रस्ताव है, लेकिन मुझे यह याद नहीं है कि क्या इसे सी ++ 20 में बनाया गया था।

तो यह जो आप देख रहे हैं उसके विपरीत की तरह है क्योंकि यह पहले से गलत रूप से अनुमानित कोड को पूर्वव्यापी तय करता है।


ट्रिगर भाग इस प्रश्न का उत्तर नहीं है - यह एक मौन परिवर्तन नहीं है। और, IIANM, दूसरा भाग कार्यान्वयन-परिवर्तन का है जो कड़ाई से अनिवार्य व्यवहार के लिए परिभाषित किया गया है, जो कि मैंने जो पूछा उसके बारे में भी नहीं है।
einpoklum

10

मुझे यकीन नहीं है कि आप इसे कोड को सही करने के लिए एक परिवर्तन को मानेंगे, लेकिन ...

C ++ 11 से पहले, कंपाइलरों को अनुमति दी गई थी, लेकिन आवश्यक नहीं है, कुछ परिस्थितियों में प्रतियों को कॉपी करने के लिए, तब भी जब कॉपी कंस्ट्रक्टर के पास अवलोकन दुष्प्रभाव होते हैं। अब हमने कॉपी इलीगेशन की गारंटी दी है। व्यवहार अनिवार्य रूप से कार्यान्वयन से परिभाषित आवश्यक हो गया।

इसका मतलब है कि आपके कॉपी कंस्ट्रक्टर साइड इफेक्ट पुराने संस्करणों के साथ हो सकते हैं, लेकिन नए के साथ कभी नहीं होंगे । आप तर्क दे सकते हैं कि सही कोड कार्यान्वयन-परिभाषित परिणामों पर निर्भर नहीं होना चाहिए, लेकिन मुझे नहीं लगता कि ऐसा कहना बिलकुल गलत है।


1
मैंने सोचा कि यह "आवश्यकता" C ++ 17 में जोड़ा गया था, C ++ 11 नहीं? ( अस्थायी
भौतिककरण

@ LCDhowie: मुझे लगता है कि तुम सही हो। जब मैंने यह लिखा था तब मेरे पास मानक नहीं थे और मैंने अपने कुछ खोज परिणामों में बहुत अधिक भरोसा किया था।
एड्रियन मैक्कार्थी

कार्यान्वयन-परिभाषित व्यवहार में परिवर्तन इस प्रश्न के उत्तर के रूप में नहीं गिना जाता है।
ईनपोकलम

7

स्ट्रीम से डेटा (संख्यात्मक) पढ़ने और विफल होने पर व्यवहार, c ++ 11 के बाद से बदल दिया गया था।

उदाहरण के लिए, किसी स्ट्रीम से पूर्णांक पढ़ना, जबकि इसमें पूर्णांक शामिल नहीं है:

#include <iostream>
#include <sstream>

int main(int, char **) 
{
    int a = 12345;
    std::string s = "abcd";         // not an integer, so will fail
    std::stringstream ss(s);
    ss >> a;
    std::cout << "fail = " << ss.fail() << " a = " << a << std::endl;        // since c++11: a == 0, before a still 12345 
}

चूँकि c ++ 11 पढ़े गए पूर्णांक को 0 पर सेट करेगा जब यह विफल हुआ; c ++ <11 पर पूर्णांक नहीं बदला गया था। कहा कि, gcc, यहां तक ​​कि जब मानक वापस c ++ 98 (-std = c ++ 98) के लिए हमेशा मजबूर किया जाता है, तो संस्करण 4.4.7 के बाद से कम से कम नया व्यवहार दिखाता है।

(Imho पुराने व्यवहार वास्तव में बेहतर था: मान को 0 में क्यों बदला जाए, जो स्वयं मान्य है, जब कुछ भी नहीं पढ़ा जा सकता है?)

संदर्भ: https://en.cppreference.com/w/cpp/locale/num_get/get देखें


लेकिन रिटर्न टाइप के बारे में कोई बदलाव नहीं बताया गया है। C ++ 11 के बाद से केवल 2 समाचार अधिभार उपलब्ध हैं
सफल

क्या यह परिभाषित व्यवहार C ++ 98 और C ++ 11 दोनों में था? या व्यवहार को परिभाषित किया गया था?
ईनपोकलुम

जब cppreference.com सही है: "यदि कोई त्रुटि होती है, तो v को अपरिवर्तित छोड़ दिया जाता है। (C ++ 11 तक)" इसलिए C ++ 11 से पहले व्यवहार को परिभाषित किया गया था, और बदल दिया गया था।
DanRechtsaf

मेरी समझ में, ss> के लिए व्यवहार वास्तव में परिभाषित किया गया था, लेकिन बहुत ही सामान्य मामले के लिए जहां आप एक uninitialized चर में पढ़ रहे हैं, c ++ 11 व्यवहार एक uninitialized चर का उपयोग करेगा, जो अपरिभाषित व्यवहार है। इस प्रकार एक बहुत ही सामान्य अपरिभाषित व्यवहार के खिलाफ विफलता गार्ड पर डिफ़ॉल्ट-निर्माण।
रासमस डमगार्ड नीलसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.