2009-04-28 15 views
34

मैं, और मुझे लगता है कि कई अन्य लोगों, स्मार्ट संकेत का उपयोग कर सी ++ में असुरक्षित स्मृति आपरेशन लपेट के लिए महान सफलता मिली है, आरए II जैसी चीजों का उपयोग कर, वगैरह। हालांकि, जब आपके पास विनाशक, कक्षाएं, ऑपरेटर ओवरलोडिंग, et cetera है, तो मेमोरी प्रबंधन को लपेटना आसान है।सी के लिए स्मार्ट पॉइंटर्स/सुरक्षित मेमोरी प्रबंधन?

कोई कच्चे C99 में लिखने के लिए, जहाँ आप (कोई यमक इरादा) इंगित सुरक्षित स्मृति प्रबंधन के साथ मदद करने के लिए कर सकता है?

धन्यवाद।

उत्तर

12

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

यदि आप इसके बारे में वास्तव में चिंतित हैं, तो आप सीधे garbage collector का उपयोग करके और स्मार्ट पॉइंटर आवश्यकता को पूरी तरह से छोड़कर विचार करना चाहेंगे।

+0

यह कैसे काम करता है? यह पॉइंटर असाइनमेंट को कैसे ट्रैक कर सकता है? – Calmarius

+0

@ कलमारेस वे काम करने के कई तरीके हैं। देखें: http://en.wikipedia.org/wiki/Garbage_collection_(computer_science) –

+0

मैं देखता हूं। मैंने आपके द्वारा लिंक किए गए जीसी के बारे में पूछा। यह दावा करता है कि यह केवल malloc और realloc को बदलकर, unmodified सी प्रोग्राम पर काम करता है। लेकिन यह आवंटित ब्लॉक को इंगित करने वाले पॉइंटर्स का पता कैसे लगाता है? उन्हें कार्यक्रम में चारों ओर कॉपी किया जा सकता है। – Calmarius

3

स्टेटिक कोड विश्लेषण उपकरण जैसे splint या Gimpel पीसी-लिंट यहां सहायता कर सकते हैं - आप इन स्वचालित "निरंतर-एकीकरण" शैली निर्माण सर्वर में उन्हें तारों से "मामूली" रोक सकते हैं। (आप उन में से एक है, सही कार्य करें:? मुस्कुराहट :)

वहाँ अन्य (कुछ और अधिक महंगी) भी इस विषय पर वेरिएंट ...

+0

+1 स्थिर कोड जांच उपकरण पर अच्छा कॉल। –

2

आप Win32 में कोडिंग रहे हैं, तो आप का उपयोग करने में सक्षम हो सकता है कुछ समान करने के लिए structured exception handling। आप कुछ इस तरह कर सकता है:

foo() { 
    myType pFoo = 0; 
    __try 
    { 
     pFoo = malloc(sizeof myType); 
     // do some stuff 
    } 
    __finally 
    { 
     free pFoo; 
    } 
} 

काफी के रूप में आसान नहीं आरए II के रूप में, आप एक ही स्थान पर अपने सफाई कोड के सभी इकट्ठा करने और गारंटी है कि यह क्रियान्वित किया जाता है सकते हैं।

8

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

4

आप सी में स्मार्ट संकेत नहीं कर सकते, क्योंकि यह आवश्यक वाक्य रचना प्रदान नहीं करता है, लेकिन आप अभ्यास के साथ लीक से बच सकते हैं। संसाधन आवंटन कोड को आवंटित करने के तुरंत बाद लिखें। इसलिए जब भी आप malloc लिखते हैं, तो आपको तुरंत क्लीनअप अनुभाग में free लिखना चाहिए।

int foo() 
{ 
    int *resource = malloc(1000); 
    int retVal = 0; 
    //... 
    if (time_to_exit()) 
    { 
     retVal = 123; 
     goto cleanup; 
    } 
cleanup: 
    free(resource); 
    return retVal; 
} 

सी में हम भी संदर्भों जो सामान का आवंटन का एक बहुत का उपयोग करें, एक ही नियम है कि के लिए भी लागू किया जा सकता:

int initializeStuff(Stuff *stuff) 
{ 
    stuff->resource = malloc(sizeof(Resource)); 
    if (!stuff->resource) 
    { 
     return -1; ///< Fail. 
    } 
    return 0; ///< Success. 
} 

void cleanupStuff(Stuff *stuff) 
{ 
    free(stuff->resource); 
} 

सीआई में 'गोटो सफाई' पैटर्न एक बहुत देखते हैं

यह ऑब्जेक्ट कन्स्ट्रक्टर और विनाशकों के समान है। जब तक आप आवंटित संसाधनों को अन्य वस्तुओं को नहीं देते हैं, तब तक यह रिसाव नहीं होगा और पॉइंटर्स लटक नहीं पाएंगे।

ऐसा नहीं है कि आवंटन ट्रैक करता है और लीक ब्लॉक atexit लिखते हैं एक कस्टम संभाजक लिखने के लिए मुश्किल नहीं है।

यदि आपको आवंटित संसाधनों को पॉइंटर्स देने की आवश्यकता है तो आप इसके लिए रैपर संदर्भ बना सकते हैं और प्रत्येक ऑब्जेक्ट संसाधन के बजाय एक रैपर संदर्भ का मालिक है। ये रैपर संसाधन और काउंटर ऑब्जेक्ट साझा करते हैं, जो उपयोग को ट्रैक करता है और ऑब्जेक्ट को मुक्त करता है जब कोई इसका उपयोग नहीं करता है। इस प्रकार सी ++ 11 के shared_ptr और weak_ptr काम करता है। यह यहां अधिक विस्तार से लिखा गया है: How does weak_ptr work?

2

आप मैक्रोज़ को परिभाषित कर सकते हैं, उदाहरण के लिए BEGIN और END, ब्रेसिज़ के स्थान पर उपयोग किए जाने और संसाधनों के स्वचालित विनाश को ट्रिगर करने के लिए जो उनके दायरे से बाहर निकलते हैं। इसकी आवश्यकता है कि ऐसे सभी संसाधनों को स्मार्ट पॉइंटर्स द्वारा इंगित किया जाता है जिसमें ऑब्जेक्ट के विनाशक को पॉइंटर भी शामिल होता है। मेरे कार्यान्वयन में मैं ढेर मेमोरी में स्मार्ट पॉइंटर्स का ढेर रखता हूं, एक दायरे में प्रवेश पर स्टैक पॉइंटर को याद करता हूं, और स्कोप निकास (रिटर्न के लिए ईएनडी या मैक्रो प्रतिस्थापन) पर यादगार स्टैक पॉइंटर के ऊपर सभी संसाधनों के विनाशकों को कॉल करता हूं। यह अच्छी तरह से काम करता है भले ही setjmp/longjmp अपवाद तंत्र का उपयोग किया जाता है, और कैच-ब्लॉक और उस क्षेत्र के बीच सभी मध्यवर्ती क्षेत्रों को साफ़ करता है जहां अपवाद फेंक दिया गया था। कार्यान्वयन के लिए https://github.com/psevon/exceptions-and-raii-in-c.git देखें।

12

सवाल थोड़ा पुराना है, लेकिन मुझे लगता है मैं लिंक करना समय लगेगा लगा मेरी जीएनयू compilers के लिए smart pointer library (जीसीसी, बजना, आईसीसी, MinGW, ...)।

इस कार्यान्वयन सफाई चर विशेषता, एक जीएनयू विस्तार पर निर्भर करता है, जब दायरे से बाहर जा रहा है स्वचालित रूप से स्मृति को मुक्त करने, और इस तरह के रूप में, नहीं आईएसओ C99, लेकिन C99 जीएनयू एक्सटेंशन के साथ है।

उदाहरण:

simple1.c:

#include <stdio.h> 
#include <csptr/smart_ptr.h> 

int main(void) { 
    smart int *some_int = unique_ptr(int, 1); 

    printf("%p = %d\n", some_int, *some_int); 

    // some_int is destroyed here 
    return 0; 
} 

संकलन & वेलग्रिंड सत्र:

$ gcc -std=gnu99 -o simple1 simple1.c -lcsptr 
$ valgrind ./simple1 
==3407== Memcheck, a memory error detector 
==3407== Copyright (C) 2002-2013, and GNU GPL\'d, by Julian Seward et al. 
==3407== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info 
==3407== Command: ./simple1 
==3407== 
0x53db068 = 1 
==3407== 
==3407== HEAP SUMMARY: 
==3407==  in use at exit: 0 bytes in 0 blocks 
==3407== total heap usage: 1 allocs, 1 frees, 48 bytes allocated 
==3407== 
==3407== All heap blocks were freed -- no leaks are possible 
==3407== 
==3407== For counts of detected and suppressed errors, rerun with: -v 
==3407== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 
0
Sometimes i use this approach and it seems good :) 

Object *construct(type arg, ...){ 

    Object *__local = malloc(sizeof(Object)); 
    if(!__local) 
     return NULL; 
    __local->prop_a = arg; 
    /* blah blah */ 


} // constructor 

void destruct(Object *__this){ 

    if(__this->prop_a)free(this->prop_a); 
    if(__this->prop_b)free(this->prop_b); 

} // destructor 

Object *o = __construct(200); 
if(o != NULL) 
    ;; 

// use 

destruct(o); 

/* 
    done ! 
*/ 
संबंधित मुद्दे