2010-05-06 17 views
12

निम्नलिखित कोड पर विचार करें। विंडोज पर जबकि (आईडीई प्रयोग किया है: Visual C++) यह नहीं है:व्यवहार में अंतर (जीसीसी और विजुअल सी ++)

#include <stdio.h> 
#include <vector> 
#include <iostream> 

struct XYZ { int X,Y,Z; }; 
std::vector<XYZ> A; 

int rec(int idx) 
{ 

    int i = A.size(); 
    A.push_back(XYZ()); 
    if (idx >= 5) 
    return i; 

    A[i].X = rec(idx+1); 

    return i; 
} 

int main(){ 
    A.clear(); 
    rec(0); 
    puts("FINISH!"); 

} 

मैं कारण है कि कोड लिनक्स पर एक विभाजन गलती (Code::Blocks आईडीई प्रयोग किया जाता) देता है यह पता लगाने नहीं कर सका।

जब मैंने वास्तव में समस्या की जांच करने के लिए वालग्रिंड का उपयोग किया, तो मुझे this output मिला।

मुझे चार अलग-अलग स्थानों पर Invalid write of size 4 मिला। फिर जब मैंने विज़ुअल सी ++ का उपयोग किया तो कोड क्रैश क्यों नहीं हुआ?

क्या मुझे कुछ याद आ रही है?

+0

क्या आपको इसका उपयोग करने से पहले वेक्टर में पर्याप्त जगह आवंटित नहीं करना है?यह शुद्ध दुर्घटना है, या संभवतः सिर्फ एक अलग, तर्कसंगत रूप से अधिक दोस्ताना लेकिन कम मानक, 'वेक्टर <>' के कार्यान्वयन। –

+0

आप जिस आईडीई का उपयोग कर रहे हैं वह बहुत उपयोगी जानकारी नहीं है। आप जिस प्रासंगिक कंपाइलर का उपयोग कर रहे हैं उसके कौन से संस्करण अधिक उपयुक्त हैं। –

+0

@ डेनिस: मैंने जीसीसी 4.3 और एमएसवीसी ++ 2008 –

उत्तर

17

rec() पर रिकर्सिव कॉल वेक्टर को संशोधित कर सकता है जबकि आप इसे मान निर्दिष्ट कर रहे हैं।

अगर आप

int tmp = rec(idx+1); 
A[i].X = tmp; 

साथ

A[i].X = rec(idx+1); 

की जगह क्या होता है?

इसके अलावा, बस उपयोगी टिप्पणियों संक्षेप में प्रस्तुत करने: एक = आपरेशन के संकार्य मूल्यांकन आदेश अनिर्दिष्ट है और के बाद से वेक्टर पूर्व आबंटित नहीं किया गया था, कई आकार बदलता rec() लिए एक पुनरावर्ती कॉल के दौरान हो सकता है, इस प्रकार में मूल्यों के लिए किसी भी इटरेटर अमान्य वेक्टर

+4

रिकर्सिव कॉल के अंदर थोड़ा और सटीक होने के लिए, 'push_back' पर कॉल पिछले पॉइंटर्स को अमान्य कर सकता है। –

+2

मूल रूप से 'i = ++ i;' मुद्दा नहीं हो सकता है (दाएं तरफ ए के संशोधन को छोड़कर रिकर्सिव कॉल में छिपा हुआ है)? कंपाइलर 'आर [i] 'का मूल्यांकन करने के लिए स्वतंत्र है' आर 'के पहले या बाद में और चाहे वह" काम करता है ", इस पर निर्भर करता है कि यह किस क्रम में ऐसा करने का विकल्प चुनता है। – UncleBens

+2

@ereOn: हाँ! मुझे लगता है कि आपका जवाब सही है। "=" ऑपरेटर से जुड़े ऑपरेंड के मूल्यांकन का क्रम _unspecified_ है। –

0

आप int i = A.size()

उपयोग कर रहे हैं और फिर आप एक सरणी के रूप में अपने struct का अनुक्रमण रहे हैं, लेकिन आकार मान का उपयोग कर। आपको इसे 1 से कम करने की आवश्यकता है A[i-1].X = rec(idx+1);

आह मेरी गलती - मैंने वेक्टर push_back का खाता नहीं लिया।

+2

लेकिन वह 'वेक्टर' में तत्व जोड़ने के बाद 'आकार()' परिणाम * के आधार पर अनुक्रमण करता है। उस बिंदु पर सूचकांक ठीक है। एक सटीक स्पष्टीकरण देने के लिए –

1

मुझे "* ऑब्जेक्ट 0x300180 के लिए त्रुटि मिलती है: मुक्त ऑब्जेक्ट के लिए गलत चेकसम - ऑब्जेक्ट को मुक्त होने के बाद संशोधित किया गया था। *" जब मैं उस कोड को चलाता हूं।

जैसा कि मुझे याद है, A[i].X = rec(idx+1) में तीन अनुक्रम अंक हैं। जब ऑपरेटर [] को ए पर बुलाया जाता है, जब आरईसी कहा जाता है, और अंत में। लेकिन पहले दो का आदेश अनिर्दिष्ट है। इसलिए यदि g ++ A[i] पहले गणना करता है, और फिर rec(idx+1) पर कॉल करता है, तो recA[i] द्वारा लौटाए गए संदर्भ को वेक्टर की आंतरिक मेमोरी के पुनर्वितरण द्वारा अमान्य कर दिया गया हो सकता है। वीसी ++ के तहत, यह rec(idx+1) का मूल्यांकन कर सकता है, इसलिए सभी push_back कॉल सामने किए गए हैं, जिसका अर्थ है कि A[i] कॉल मेमोरी के सही ब्लॉक को संदर्भित करती हैं। वैकल्पिक रूप से, यह चीजों को वैसे ही कर सकता है, और आप बस segfault नहीं होता ... यह अपरिभाषित व्यवहार की समस्याओं में से एक है।

std::vector<XYZ> A; से std::vector<XYZ> A(10); बदलकर 10 तत्वों के लिए पर्याप्त स्थान आरक्षित होगा। यह rec के आपके विशिष्ट कार्यान्वयन को कभी भी पुन: आवंटित करने से रोकता है, और यह मेरे अंत में त्रुटि को हल करता है।

+1

+1 :) –

+0

-1। यह समाधान निश्चित रूप से उस पल तक काम करेगा जहां आप अधिकतम रिकर्सिव मान 11 को बढ़ाते हैं। – deworde

+0

@ डिवार्ड: जाहिर है, इसलिए योग्यता है कि यह अपने विशिष्ट कार्यान्वयन को पुन: आवंटित करने से रोकती है। –

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