2010-11-10 22 views
5

मुझे समझ में क्यों यह एक segfault कारण बनता है:std :: कॉपी और std :: वेक्टर समस्या

#include <algorithm> 
#include <vector> 
using namespace std; 

int main() 
{ 
    vector<int> v; 
    int iArr[5] = {1, 2, 3, 4, 5}; 
    int *p = iArr; 

    copy(p, p+5, v.begin()); 

    return 0; 
} 

लेकिन क्यों यह एक segfault का कारण नहीं है?

#include <algorithm> 
#include <vector> 
using namespace std; 

int main() 
{ 
    vector<int> v; 
    int iArr[5] = {1, 2, 3, 4, 5}; 
    int *p = iArr; 

    v.reserve(1); 
    copy(p, p+5, v.begin()); 

    return 0; 
} 
+0

@ केनीटीएम 1 तत्व –

+0

के लिए दूसरी आरक्षित जगह सी ++ में अपरिभाषित व्यवहार के विभिन्न प्रकार से संबंधित एक अच्छा जवाब था: http://stackoverflow.com/questions/367633/what-are-all-the-common- अपरिभाषित-व्यवहार-वह-एसी-प्रोग्रामर-चाहिए-पता-अबो/367662 # 367662 –

+7

आप 'कॉपी (पी, पी +5, बैक_इन्सेटर (v)) का उपयोग क्यों नहीं करते हैं, और इस गड़बड़ी से बचें? –

उत्तर

7

इस अपरिभाषित व्यवहार है - reserve()कम से कम एक तत्व के लिए एक बफर आवंटित और तत्व अप्रारंभीकृत छोड़ दिया है।

तो या तो बफर काफी बड़ा है और इसलिए आप तकनीकी रूप से पहले से परे तत्वों तक पहुंच सकते हैं या यह पर्याप्त नहीं है और आप किसी भी समस्या का पालन नहीं करते हैं।

नीचे की रेखा है - ऐसा मत करें। केवल उन तत्वों तक पहुंचें जिन्हें कानूनी रूप से vector उदाहरण में संग्रहीत किया गया है।

+0

मैं तत्वों की प्रतिलिपि बनाने से पहले 'रिजर्व() '' रिजर्व() 'से अधिक' रिजर्व()' को कॉल करना पसंद करूंगा - अन्यथा आप तत्वों को पुन: सक्रिय नहीं कर सकते हैं और 'आकार() 'अभी भी 0 लौटाएगा, साथ ही अगला' push_back()' will आपने जो कॉपी किया है उसे ओवरराइट करना शुरू करें। – AshleysBrain

+0

मुझे मिल गया। मुझे 'आरक्षित() 'के बजाय' आकार बदलना चाहिए)। दोनों के बीच क्या अंतर है? – nakiya

+0

@nakiya: कुंजी को कृपया बड़े पैमाने पर पर्याप्त बफर आवंटित करने के लिए 'वेक्टर' से पूछना है, अन्यथा यह यूबी है। – sharptooth

0

क्योंकि आप दुर्भाग्यपूर्ण थे। आवंटित स्मृति तक पहुंच यूबी नहीं है।

2

यह गलत है! यह आपके द्वारा स्वामित्व वाली स्मृति तक पहुंचने के लिए अपरिभाषित व्यवहार है, भले ही यह किसी उदाहरण में काम करता हो। कारण, मुझे लगता है कि std::vector एक से अधिक तत्व आरक्षित करेगा।

0

सबसे अधिक संभावना है क्योंकि एक खाली वेक्टर में आवंटित कोई स्मृति नहीं है, इसलिए आप एक नल पॉइंटर को लिखने की कोशिश कर रहे हैं जो आम तौर पर तत्काल दुर्घटना की ओर जाता है। दूसरे मामले में इसमें कम से कम कुछ स्मृति आवंटित की गई है, और आप संभवतया किसी सरणी के अंत को ओवरराइट कर रहे हैं जो C++ में क्रैश का कारण बन सकता है या नहीं।

दोनों गलत हैं।

6

दोनों गलत हैं क्योंकि आप खाली वेक्टर की प्रतिलिपि बना रहे हैं और प्रतिलिपि की आवश्यकता है कि आपके पास सम्मिलन के लिए स्थान हो। यह कंटेनर का आकार बदलता नहीं है।

copy(p, p+5, back_inserter(v)); 
0

यह गलत होगा जिस तरह से, यहां तक ​​कि वेक्टर के लिए 1 तत्व कॉपी करने के लिए इस तरह (या 5 तो आरक्षित कि जिस तरह से कॉपी करने के लिए): क्या आप शायद यहाँ की जरूरत है back_insert_iterator और back_inserter है।

कारण यह सबसे अधिक संभावना SEGFAULT यह नहीं है कि implementor लगा कि यह सिर्फ मामले में आप इसे बाद में विकसित करने के लिए करना चाहता था में सिर्फ 1 तत्व के लिए स्मृति को आबंटित करने अक्षम होगा, इसलिए हो सकता है कि वे 16 या 32 तत्वों के लिए पर्याप्त आवंटित है।

कर रिजर्व (5) पहले तो 5 तत्वों में लिख सीधे शायद अपरिभाषित व्यवहार नहीं होगा, बल्कि इसलिए वेक्टर अभी तक 5 के एक तार्किक आकार की जरूरत नहीं होगी और प्रति लगभग "बर्बाद" किया जाएगा के रूप में वेक्टर दावा करेंगे सही नहीं होगा और अभी भी 0

वैध व्यवहार क्या होगा (5), एक तत्व डालें, कहीं भी इसके इटरेटर को स्टोर करें, 4 और तत्व डालें और पहले इटरेटर की सामग्री देखें। आरक्षित() गारंटी देता है कि जब तक वेक्टर उस आकार से अधिक नहीं हो जाता है या मिट(), स्पष्ट(), आकार बदलें() या अन्य रिजर्व() को कॉल किया जाता है, तब तक इटरेटर्स अमान्य नहीं होते हैं।

2

लेकिन यह segfault क्यों नहीं बनाता है?

क्योंकि तारों को गठबंधन किया गया है। या आप डीबग में चल रहे थे और कंपाइलर ने आपको "मदद" करने के लिए कुछ किया था। निचली पंक्ति यह है कि आप गलत काम कर रहे हैं, और अपरिभाषित व्यवहार की अंधेरे और नोडेटर्मेनिस्टिक दुनिया में पार हो गए हैं।वे reserve वेक्टर में एक स्थान और फिर reserve -ed स्पेस में 5 तत्वों को क्रैक करने का प्रयास करें। खराब।

आपके पास 3 विकल्प हैं। वरीयता के अपने व्यक्तिगत क्रम में:

1) back_insert_iterator का उपयोग करें जो इस उद्देश्य के लिए डिज़ाइन किया गया है। यह #include <iterator> द्वारा प्रदान किया जाता है। वाक्य रचना थोड़ा अजीब है, लेकिन सौभाग्य से एक अच्छा चीनी लेपित शॉर्टकट, back_inserter भी प्रदान की जाती है:

#include <iterator> 
// ... 
copy(p, p+5, back_inserter(v)); 

2) assign वेक्टर के तत्वों। मैं इस विधि को थोड़ा कम पसंद करता हूं क्योंकि assignvector का सदस्य है, और यह मुझे algorithm से somethign का उपयोग करने से थोड़ा कम सामान्य के रूप में हमला करता है।

v.assign(p, p+5); 

3) reserve तत्वों की सही संख्या, फिर उन्हें कॉपी। मैं किसी भी कारण से सबकुछ विफल होने पर यह आखिरी खाई का प्रयास मानता हूं। यह इस तथ्य पर निर्भर करता है कि vector का भंडारण संगत है इसलिए यह सामान्य नहीं है, और यह vector में डेटा प्राप्त करने की बैक-दरवाजा विधि की तरह लगता है।

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