संकलित समय पर हटाने के लिए [] बनाम नष्ट करने का गलत पता लगाना


19

मैं जानना चाहूंगा कि क्या deleteसंकलन समय पर नीचे दी गई त्रुटि का पता लगाना संभव है ? विशेष रूप से, मैं g ++ कंपाइलर के बारे में सुनना चाहूंगा।

ClassTypeA *abc_ptr = new ClassTypeA[100];  
abc_ptr[10].data_ = 1;  
delete abc_ptr; // error, should be delete []  

7
आपको वैसे भी मैन्युअल रूप से कॉल डिलीट नहीं करना चाहिए।
मार्टिन यॉर्क

9
@LokiAstari क्या आपको वास्तव में लगता है कि टिप्पणी सहायक थी?
जेम्स

5
@ नाम: हाँ। कुंजी "मैन्युअल रूप से" है।
मार्टिन यॉर्क

कभी-कभी इसका अनुपालन करने के लिए विरासत कोड का एक बहुत कुछ फिर से लिखना शामिल होगा
निक किघ्ले

उपयोग करें std::unique_ptr<ClassTypeA[]>और फिर आपको इसकी आवश्यकता नहीं है।
user253751

जवाबों:


6

सामान्य तौर पर, कंपाइलर ऐसी त्रुटियों का पता नहीं लगा सकता है। उदाहरण: मान लीजिए कि कुछ वर्ग के लिए कंस्ट्रक्टर कुछ डेटा सदस्य का उपयोग करके आवंटित new TypeName[]करता है, लेकिन विध्वंसक गलती से deleteइसके बजाय का उपयोग करता हैdelete[] । यदि कंस्ट्रक्टर और डिस्ट्रॉक्टर को अलग-अलग संकलनों इकाइयों में परिभाषित किया गया है, तो संकलक को यह पता कैसे चलता है कि फाइल को संकलित करते समय विध्वंसक को परिभाषित करता है कि उपयोग असंगत रूप से संकलित फ़ाइल में है जो कंस्ट्रक्टर को परिभाषित करता है?

GNU संकलक के संबंध में, यह नहीं है। जैसा कि ऊपर उल्लेख किया गया है, यह सामान्य मामले में ऐसा नहीं कर सकता। एक कंपाइलर को ऐसी बेमेल नई / डिलीट त्रुटियों का पता लगाने की आवश्यकता नहीं है क्योंकि यह अपरिभाषित व्यवहार है। यूबी संकलक विक्रेता का "जेल से बाहर निकलना" कार्ड है।

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


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

28

आप उपयुक्त RAII कक्षाओं का उपयोग कर सकते हैं delete। यह ऐसा करने का एकमात्र सुरक्षित तरीका है, और यह त्रुटि केवल एक ही है, बहुत से आप deleteअपने आप को कॉल करने का सामना करेंगे ।

हमेशा गतिशील जीवनशैली संसाधनों के प्रबंधन के लिए कक्षाओं का उपयोग करें, और प्रकार प्रणाली सही संसाधन विनाश को लागू करेगी।

संपादित करें: "क्या होगा यदि आप कोड का ऑडिट कर रहे हैं और इसे बदल नहीं सकते?" तुम चोदो।


18
-1 क्योंकि यह वास्तव में सवाल का जवाब नहीं देता है।
मेसन व्हीलर

2
बेमेल का पता लगाने का एकमात्र तरीका प्रकार प्रणाली का उपयोग करना है, जिसमें RAII कक्षाओं का उपयोग करना शामिल है।
डेडएमजी

9
... वह भी कम समझ में आता है। आरएआईआई कक्षाओं का उपयोग क्या करता है - एक रनटाइम तंत्र - स्टैटिक प्रकार प्रणाली की जानकारी के साथ क्या करना है जो संकलनकर्ता को संकलन-समय पर पता है?
मेसन व्हीलर

6
@MasonWheeler को बढ़ावा देना :: साझा करना = उदाहरण के रूप में साझा करना और साझा करना :: साझा करना। साझा_प्रेट को नष्ट करने से ऑब्जेक्ट को नष्ट कर दिया जाता है, शेअर को साझा करते हुए शेयर को नष्ट कर दिया जाता है []। जब तक आप पहली जगह में एक सरणी के साथ एक साझा_प्राट का निर्माण नहीं करते हैं, तब तक आप एक share_ptr को एक share_ptr को असाइन नहीं कर सकते, इसलिए - टाइप सिस्टम गलत डिलीट को रोकता है।
पीट किर्कम

4
आम तौर पर, इस तरह का एक उत्तर सहायक की तुलना में अधिक अप्रिय है। हालांकि, इस मामले में, यह वास्तव में सच है। वह एक सामान्य त्रुटि के कंपाइलर प्रवर्तन की तलाश कर रहा है, और RAII का उपयोग करने से त्रुटि की इस शैली को ठीक से रोकता है, जिससे वह वास्तव में वही चाहता है जो वह चाहता है। +1
रिवलॉक

10

यह विशेष त्रुटि - हाँ। इस तरह की त्रुटि आम तौर पर: दुर्भाग्य से, नहीं! इसमें वास्तव में इसे निष्पादित किए बिना निष्पादन के प्रवाह की भविष्यवाणी करना शामिल होगा, और यह मनमाने कार्यक्रमों के लिए संभव नहीं है। (यही कारण है कि अधिकांश संकलक आपके उदाहरण जैसे सरल मामलों का पता लगाने की कोशिश भी नहीं करते हैं।)

इसलिए डेडएमजी का उत्तर उपयुक्त है: ध्यान देकर इसे ठीक करने का प्रयास न करें - मानव का ध्यान गिरने योग्य है। भाषा-उपलब्ध साधनों का उपयोग करें और कंप्यूटर पर ध्यान दें।


इसे निष्पादन के प्रवाह की भविष्यवाणी करने की आवश्यकता कैसे होती है? यह मुझे पूरी तरह से स्थिर, संकलन-समय के ज्ञान की तरह लगता है; संकलक के प्रकार प्रणाली को पता है कि एक सरणी क्या है और क्या नहीं है।
मेसन व्हीलर

जातियों की उपस्थिति में भी? क्षमा करें, अगर मुझे वह गलत मिला तो मैं उत्तर हटा दूंगा।
किलन फ़ॉथ

12
@MasonWheeler का स्थिर प्रकार abc_ptr है, ClassTypeA*इसलिए आप नए और डिलीट के बीच एक लाइन डाल सकते हैं और if ( rand() % 2 == 1 ) abc_ptr = new ClassTypeA;स्टेटिक टाइप सिस्टम में कुछ भी नहीं दिखा रहा है कि किसी abc_ptrपॉइंट या डायनामिक ऑब्जेक्ट पर पॉइंट है या किसी अन्य ऑब्जेक्ट या एरे में।
पीट किर्कम

...अरे हाँ। मुझे वास्तविक सरणी प्रकार वाली भाषाओं के साथ काम करने की इतनी आदत है कि मैं यह भूल जाता रहता हूं कि सी-लैंड में यह कितना खराब है। :(
मेसन व्हीलर

1
@ पे किर्कम, @ मेसन व्हीलर: लेकिन फिर भी, रनटाइम को यह देखना चाहिए कि पता द्वारा बताई गई पते पर कितनी वस्तुएं संग्रहीत हैं abc_ptr, अन्यथा यह मेमोरी की सही मात्रा को कैसे निपटा सकता है? तो रनटाइम जानता है कि कितनी वस्तुओं को निपटाया जाना चाहिए।
जियोर्जियो

4

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

क्यों संभव नहीं है कि विशेष मामलों का निदान करें?

C ++ में पहले से ही डायनेमिक संसाधनों के रिसाव से निपटने के लिए उपकरण मौजूद हैं, जो स्कोप्स, यानी स्मार्ट पॉइंटर्स और उच्च स्तरीय सरणियों ( std::vector) से जुड़े हैं।

यहां तक ​​कि अगर आप सही deleteस्वाद का उपयोग करते हैं , तो भी आपका कोड अभी भी सुरक्षित नहीं है। यदि डायनामिक एग्जिट द्वारा कोड new[]और delete[]टर्मिनेट किया जाता है, तो विलोपन कभी भी निष्पादित नहीं होता है।

जहाँ तक रन-टाइम डिटेक्शन जाता है, Valgrindटूल रन-टाइम पर इसका पता लगाने का अच्छा काम करता है। घड़ी:

==26781== Command: ./a.out
==26781==
==26781== Mismatched free() / delete / delete []
==26781==    at 0x402ACFC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==26781==    by 0x8048498: main (in /home/kaz/test/a.out)
==26781==  Address 0x4324028 is 0 bytes inside a block of size 80 alloc'd
==26781==    at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==26781==    by 0x8048488: main (in /home/kaz/test/a.out)

बेशक, Valgrind सभी प्लेटफार्मों पर नहीं चलता है, और यह उपकरण के तहत सभी रन-टाइम स्थितियों को पुन: पेश करने के लिए हमेशा व्यावहारिक या संभव नहीं है।


आप कहते हैं कि संकलन समय पर इस तुच्छ मामले का पता लगाया जा सकता है। क्या आप मुझे बता सकते हैं कि आप इसे हासिल करने के लिए किस संकलन का उपयोग करते हैं?
एसबीजीआर

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

-3

संकलन-समय / स्थैतिक-विश्लेषण-समय पर पता लगाने के कुछ तुच्छ उदाहरण:

RHEL7 होस्ट के साथ cppcheck 1.77 and 1.49

> cat test.cc
#include <memory>
int main(){char* buf = new char[10];delete buf;}

http://cppcheck.sourceforge.net/

> cppcheck -x c++ test.cc
Checking test.cc ...
[test.cc:2]: (error) Mismatching allocation and deallocation: buf

साथ clang++ 3.7.1RHEL7 पर

> clang++ --analyze -x c++ test.cc
test.cc:2:37: warning: Memory allocated by 'new[]' should be deallocated by
'delete[]', not 'delete'
int main(){char* buf = new char[10];delete buf;}
                                    ^~~~~~~~~~
1 warning generated.

क्लैंग स्टेटिक एनालाइजर भी पता लगा सकता std::unique_ptrहै कि कब पास नहीं हुआ है<char[]>

> cat test2.cc
#include <memory>
int main(){std::unique_ptr<char> buf(new char[10]);}

https://clang-analyzer.llvm.org/

> clang++ --analyze -x c++ -std=c++11 test2.cc
In file included from test2.cc:1:
In file included from /opt/rh/devtoolset-4/root/usr/lib/gcc/x86_64-redhat-linux/5.3.1/
../../../../include/c++/5.3.1/memory:81:
/opt/rh/devtoolset-4/root/usr/lib/gcc/x86_64-redhat-linux/5.3.1/
../../../../include/c++/5.3.1/bits/unique_ptr.h:76:2: 
warning: Memory allocated by
      'new[]' should be deallocated by 'delete[]', not 'delete'
        delete __ptr;
        ^~~~~~~~~~~~
1 warning generated.

काम के लिंक के साथ नीचे अपडेट करें जिसने इसे क्लैंग, परीक्षणों और एक बग जो मुझे मिला था।

इसे समीक्षाओं के साथ जोड़ा गया था ।llvm.org/D4661 - "नए का पता लगाएं और 'हटाएं" का उपयोग करें

टेस्ट टेस्ट / एनालिसिस / मिसमैचडेललोकैक्टर- टैक्टर-टैस्ट.एमएम हैं

मुझे यह खुला बग मिला - बगैसलेवम। Com /show_bug.cgi?id=24819


कोई भी संदेह नहीं है कि आप एक स्थिर विश्लेषक पा सकते हैं जो एक विशिष्ट गलत उपयोग का पता लगाता है , बजाय एक जो सभी गलत उपयोगों का पता लगाता है (और उम्मीद है कि कोई गलत उपयोग नहीं करता है )
Caleth
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.