क्यों #include <string> यहां स्टैक ओवरफ्लो त्रुटि को रोका जा रहा है?


121

यह मेरा नमूना कोड है:

#include <iostream>
#include <string>
using namespace std;

class MyClass
{
    string figName;
public:
    MyClass(const string& s)
    {
        figName = s;
    }

    const string& getName() const
    {
        return figName;
    }
};

ostream& operator<<(ostream& ausgabe, const MyClass& f)
{
    ausgabe << f.getName();
    return ausgabe;
}

int main()
{
    MyClass f1("Hello");
    cout << f1;
    return 0;
}

यदि मैं टिप्पणी करता #include <string>हूं कि मुझे कोई संकलक त्रुटि नहीं मिलती है, तो मुझे लगता है क्योंकि यह एक तरह से शामिल है #include <iostream>। अगर मैं Microsoft VS में "राइट-क्लिक -> डेफिनिशन पर जाएं" तो वे दोनों xstringफाइल में एक ही लाइन को इंगित करते हैं:

typedef basic_string<char, char_traits<char>, allocator<char> >
    string;

लेकिन जब मैं अपना कार्यक्रम चलाता हूं, मुझे एक अपवाद त्रुटि मिलती है:

OperatorString.exe में 0x77846B6E (ntdll.dll): 0xC00000FD: ढेर अतिप्रवाह (पैरामीटर: 0x00000001, 0x01202FC4)

कोई भी विचार क्यों मुझे टिप्पणी करते समय एक रनटाइम त्रुटि मिलती है #include <string>? मैं वीएस 2013 एक्सप्रेस का उपयोग कर रहा हूं।


4
भगवान की कृपा से। जीसीसी पर पूरी तरह से काम करते हुए, ideone.com/YCf4OI
v78

क्या आपने दृश्य c ++ के साथ दृश्य स्टूडियो की कोशिश की और टिप्पणी में शामिल हैं <string>?
एयरबोर्न

1
@cbuchart: हालांकि इस सवाल का जवाब पहले ही दिया जा चुका था, लेकिन मुझे लगता है कि यह एक जटिल विषय है जो अलग-अलग शब्दों में दूसरा जवाब देना मूल्यवान है। मैंने आपके महान उत्तर को मिटाने के लिए मतदान किया है।
लाइटनेस दौड़ ऑर्बिट में

5
@Ruslan: प्रभावी रूप से, वे हैं। यह कहना है, #include<iostream>और <string>दोनों शामिल हो सकते हैं <common/stringimpl.h>
MSalters

3
विजुअल स्टूडियो 2015 में, आपको ...\main.cpp(23) : warning C4717: 'operator<<': recursive on all control paths, function will cause runtime stack overflowइस लाइन को चलाने की चेतावनी मिलती हैcl /EHsc main.cpp /Fetest.exe
क्रोको

जवाबों:


161

वास्तव में, बहुत दिलचस्प व्यवहार।

कोई भी विचार क्यों मुझे टिप्पणी करते समय मुझे रनटाइम त्रुटि मिलती है #include <string>

एमएस वीसी ++ कंपाइलर के साथ त्रुटि होती है क्योंकि यदि आप नहीं करते हैं तो आपने इसके लिए परिभाषित #include <string>नहीं operator<<किया है std::string

जब संकलक संकलन करने की कोशिश करता है तो ausgabe << f.getName();यह operator<<परिभाषित के लिए दिखता है std::string। चूंकि यह परिभाषित नहीं था, इसलिए कंपाइलर विकल्पों की तलाश करता है। के लिए एक operator<<परिभाषित है MyClassऔर संकलक इसका उपयोग करने की कोशिश करता है, और इसका उपयोग करने के लिए इसे परिवर्तित std::stringकरना पड़ता है MyClassऔर ठीक यही होता है क्योंकि MyClassएक गैर-स्पष्ट निर्माता होता है! इसलिए, कंपाइलर आपके एक नए उदाहरण का निर्माण MyClassकरता है और इसे फिर से आपके आउटपुट स्ट्रीम में स्ट्रीम करने की कोशिश करता है। यह एक अंतहीन पुनरावृत्ति का परिणाम है:

 start:
     operator<<(MyClass) -> 
         MyClass::MyClass(MyClass::getName()) -> 
             operator<<(MyClass) -> ... goto start;

त्रुटि से बचने के लिए आपको #include <string>यह सुनिश्चित करने की आवश्यकता है कि कोई operator<<परिभाषित है std::stringMyClassइस प्रकार के अप्रत्याशित रूपांतरण से बचने के लिए आपको अपने निर्माता को स्पष्ट करना चाहिए । ज्ञान का नियम: निर्माण करने वालों को स्पष्ट करें कि क्या वे निहितार्थ से बचने के लिए केवल एक तर्क लेते हैं:

class MyClass
{
    string figName;
public:
    explicit MyClass(const string& s) // <<-- avoid implicit conversion
    {
        figName = s;
    }

    const string& getName() const
    {
        return figName;
    }
};

ऐसा लगता है कि operator<<के लिए std::stringकेवल परिभाषित हो जाता है जब <string>(एमएस संकलक के साथ) और यही कारण है सब कुछ compiles के लिए शामिल किया गया है, फिर भी आप कुछ हद तक अप्रत्याशित व्यवहार के रूप में पाने के operator<<लिए रिकर्सिवली बुलाया जा रहा है MyClassके बजाय फोन करने के operator<<लिए std::string

इसका मतलब यह है कि #include <iostream>स्ट्रिंग के माध्यम से केवल आंशिक रूप से शामिल किया गया है?

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


19
@airborne - यह "विज़ुअल C ++ विशिष्ट समस्या" नहीं है, लेकिन जब आप उचित हेडर शामिल नहीं करते हैं तो क्या हो सकता है। जब सभी प्रकार की चीजों के std::stringबिना उपयोग किया #include<string>जा सकता है, तो एक संकलन समय त्रुटि तक सीमित नहीं है। गलत फ़ंक्शन या ऑपरेटर को कॉल करना जाहिरा तौर पर एक और विकल्प है।
बो पर्सन

15
खैर, यह "गलत फ़ंक्शन या ऑपरेटर को कॉल करना" नहीं है; संकलक वही कर रहा है जो आपने इसे करने के लिए कहा था। आप सिर्फ यह नहीं जानते थे कि आप ऐसा करने के लिए कह रहे थे;)
को ऑर्बिट में लाइटनेस दौड़

18
इसके संबंधित हेडर फ़ाइल को शामिल किए बिना एक प्रकार का उपयोग करना एक बग है। अवधि। क्या कार्यान्वयन से बग को जगह मिल सकती है? ज़रूर। लेकिन यह कार्यान्वयन के साथ एक "समस्या" नहीं है , यह आपके द्वारा लिखे गए कोड के साथ एक समस्या है।
कोड़ी ग्रे

4
मानक पुस्तकालय ऐसे टोकन को शामिल करने के लिए स्वतंत्र हैं जो स्वयं के भीतर एसटीडी में कहीं और परिभाषित हैं, और यदि वे एक टोकन को परिभाषित करते हैं, तो पूरे हेडर को शामिल करने की आवश्यकता नहीं है।
यक्क - एडम नेवरामोंट

5
यह सी + + प्रोग्रामर्स के एक झुंड को देखने के लिए कुछ हास्यप्रद है जो यह तर्क देता है कि संकलक और / या मानक पुस्तकालय को उनकी मदद करने के लिए अधिक काम करना चाहिए। कार्यान्वयन मानक के अनुसार, यहां अपने अधिकारों के भीतर अच्छी तरह से है, जैसा कि कई बार बताया गया है। क्या प्रोग्रामर के लिए इसे और अधिक स्पष्ट करने के लिए "प्रवंचना" का उपयोग किया जा सकता है? ज़रूर, लेकिन हम जावा में कोड भी लिख सकते हैं और इस समस्या से पूरी तरह से बच सकते हैं। MSVC को अपने आंतरिक सहायकों को क्यों दिखाई देना चाहिए? हेडर को निर्भरता के एक समूह में क्यों खींचना चाहिए जो वास्तव में इसकी आवश्यकता नहीं है? यह भाषा की पूरी भावना का उल्लंघन करता है!
कोड़ी ग्रे

35

समस्या यह है कि आपका कोड एक अनंत पुनरावृत्ति कर रहा है। हेडर फ़ाइल में std::string( std::ostream& operator<<(std::ostream&, const std::string&)) के लिए स्ट्रीमिंग ऑपरेटर को घोषित किया जाता है <string>, हालांकि std::stringखुद को अन्य हेडर फ़ाइल (दोनों द्वारा शामिल ) <iostream>और में घोषित किया जाता है <string>

जब आप <string>संकलक को शामिल नहीं करते हैं तो संकलन करने का तरीका खोजने की कोशिश करता है ausgabe << f.getName();

ऐसा होता है कि आपने एक के लिए एक स्ट्रीमिंग ऑपरेटर MyClassऔर एक निर्माण करने वाले दोनों को परिभाषित किया है std::string, इसलिए कंपाइलर इसका उपयोग करता है ( अंतर्निहित निर्माण के माध्यम से ), एक पुनरावर्ती कॉल बनाता है।

यदि आप explicitअपने कंस्ट्रक्टर ( explicit MyClass(const std::string& s)) की घोषणा करते हैं, तो आपका कोड अब संकलित नहीं करेगा, क्योंकि स्ट्रीमिंग ऑपरेटर को कॉल करने का कोई तरीका नहीं है std::string, और आपको <string>हेडर शामिल करने के लिए मजबूर किया जाएगा ।

संपादित करें

मेरा परीक्षण वातावरण VS 2010 है, और चेतावनी स्तर 1 ( /W1) से शुरू होकर यह आपको समस्या के बारे में चेतावनी देता है:

चेतावनी C4717: 'ऑपरेटर <<': सभी नियंत्रण पथों पर पुनरावर्ती, फ़ंक्शन रनटाइम स्टैक अतिप्रवाह का कारण होगा

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