c++ - सरणी विशेषज्ञता के लिए unique_ptr<टी> लैम्ब्डा कस्टम डिलीटर




lambda c++11 (2)

इस प्रश्न का उत्तर यहां दिया गया है:

मैंने हाल ही में अपने मौजूदा सी ++ एप्लिकेशन कोड को सी ++ 11 पर पोर्ट करना शुरू कर दिया है और अब जब मैं नए स्मार्ट पॉइंटर्स std :: unique_ptr और std :: shared_ptr में परिवर्तित कर रहा हूं, तो मेरे पास कस्टम डिलीटर के बारे में एक विशिष्ट प्रश्न है। मैं यह देखने के लिए एक लैम्ब्डा लॉगर जोड़ना चाहता हूं कि मेरे डिलीट कहां जा रहे हैं लेकिन मुझे संकलन के लिए सरणी विशेषज्ञता संस्करण नहीं मिल रहा है। सलाह बहुत सराहना की जाएगी।

मैं VC ++ 10 या GCC 4.5.2+ के लिए सरणी विशेषज्ञता unique_ptr के लिए कस्टम डिलीटर के उदाहरण के लिए व्यर्थ खोज रहा हूं । मैं एक लॉग संदेश मुद्रित करना चाहता हूं जब डेलेटर को लैम्ब्डा में बुलाया जाता है - मुख्य रूप से यह सुनिश्चित करने के लिए कि सभी पॉइंटर्स जो मुझे लगता है कि दायरे से बाहर जा रहे हैं, ऐसा कर रहे हैं। क्या यह विशेषज्ञता के सरणी संस्करण के लिए संभव है? मैं इसे गैर सरणी संस्करण के साथ काम करने के लिए प्राप्त कर सकता हूं, और अगर मैं बाहरी तर्क "MyArrayDeleter" को दूसरे तर्क के रूप में पास करता हूं तो मैं इसे सरणी विशेषज्ञता के साथ काम करने के लिए भी प्राप्त कर सकता हूं। एक और बात, क्या बदसूरत std :: फ़ंक्शन को निकालना संभव होगा क्योंकि मैंने सोचा था कि मैं लैम्ब्डा हस्ताक्षर को उस आंकड़े को छोड़ सकता हूं।

struct MySimpleDeleter {
    void operator()(int* ptr) const {
        printf("Deleting int pointer!\n");
        delete ptr;
    }
};
struct MyArrayDeleter {
    void operator()(int* ptr) const {
        printf("Deleting Array[]!\n");
        delete [] ptr;
    }
};
{
    // example 1 - calls MySimpleDeleter where delete simple pointer is called
    std::unique_ptr<int, MySimpleDeleter> ptr1(new int(5));

    // example 2 - correctly calls MyArrayDeleter where delete[] is called
    std::unique_ptr<int[], MyArrayDeleter> ptr2(new int[5]);

    // example 3 - this works (but default_delete<int[]> would have been passed
    // even if I did not specialize it as it is the default second arg
    // I only show it here to highlight the problem I am trying to solve
    std::unique_ptr<int[], std::default_delete<int[]>> ptr2(new int[100]);

    // example 3 - this lambda is called correctly - I want to do this for arrays
    std::unique_ptr<int, std::function<void (int *)>> ptr3(
        new int(3), [&](int *ptr){ 
            delete ptr; std::cout << "delete int* called" << std::endl; 
        });

    // example 4 - I cannot get the following like to compile
    // PLEASE HELP HERE - I cannot get this to compile
    std::unique_ptr<int[], std::function<void (int *)>> ptr4(
        new int[4], [&](int *ptr){  
            delete []ptr; std::cout << "delete [] called" << std::endl; 
        });
}

The compiler error is as follows:

The error from the compiler (which complains about the new int[4] for ptr4 below is:
'std::unique_ptr<_Ty,_Dx>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty,_Dx>'
1>          with
1>          [
1>              _Ty=int [],
1>              _Dx=std::tr1::function<void (int *)>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 10.0\vc\include\memory(2513) : see declaration of 'std::unique_ptr<_Ty,_Dx>::unique_ptr'
1>          with
1>          [
1>              _Ty=int [],
1>              _Dx=std::tr1::function<void (int *)>
1>          ]

व्हाट अबाउट:

auto deleter=[&](int* ptr){...};
std::unique_ptr<int[], decltype(deleter)> ptr4(new int[4], deleter);

सबसे पहले, मैं एसपी 1, मिंगव जी ++ 4.7.1 के साथ वीसी -2010 का उपयोग करता हूं

सरणी के लिए नया, unique_ptr पहले से ही इसे एक साफ तरीके से समर्थन देता है:

struct X
{
    X()   { puts("ctor"); }
   ~X()   { puts("dtor"); }
};

unique_ptr<X[]>  xp(new X[3]);

आउटपुट है:

ctor
ctor
ctor
dtor
dtor
dtor

कस्टमाइज्ड डिलीटर के लिए, दुर्भाग्यवश, यह वीसी -2010 और जी ++ के बीच असंगत है:

VC2010:

  unique_ptr<FILE, function<void (FILE*)> > fp(fopen("tmp.txt", "w"), [](FILE *fp){
    puts("close file now");
    fclose(fp);
  });

जी ++:

  unique_ptr<FILE, void (*)(FILE*) > fp(fopen("tmp.txt", "w"), [](FILE *fp){
    puts("close file now");
    fclose(fp);
  });

मैनगु द्वारा विधि बहुत अच्छी है, क्योंकि इनलाइन लैम्ब्डा शांत है लेकिन पठनीयता आईएमएचओ को चोट पहुंचाती है। यह अधिग्रहण (आरएआईआई) से पहले रिलीज संसाधन को भी बढ़ा देता है।

यहां मैं संसाधन अधिग्रहण और रिलीज को अलग करने के लिए एक घोषणात्मक तरीका सुझाता हूं (स्कोप गार्ड, वीसी -2010 और जी ++ 4.7.1 दोनों के लिए काम करता है):

template<typename T>
struct ScopeGuard
{
    T deleter_;
    ScopeGuard( T deleter) : deleter_(deleter) {}
    ~ScopeGuard() { deleter_() ; }
};
#define UNI_NAME(name, line) name ## line
#define ON_OUT_OF_SCOPE_2(lambda_body, line) auto UNI_NAME(deleter_lambda_, line) = [&]() {    lambda_body; } ; \
       ScopeGuard<decltype(UNI_NAME(deleter_lambda_, line))> \
       UNI_NAME(scope_guard_, line)  ( UNI_NAME(deleter_lambda_, line ));
#define ON_OUT_OF_SCOPE(lambda_body) ON_OUT_OF_SCOPE_2(lambda_body, __LINE__)

FILE * fp = fopen("tmp.txt", "w");
ON_OUT_OF_SCOPE( { puts("close file now"); fclose(fp); } );

मुद्दा यह है कि आप पुराने, स्पष्ट तरीके से संसाधन प्राप्त कर सकते हैं और संसाधन-अधिग्रहण लाइन के तुरंत बाद संसाधन को जारी करने के लिए बयान घोषित कर सकते हैं।

दोष यह है कि आप इसके एक ही ऑब्जेक्ट को इसके डिलीटर के साथ आगे नहीं बढ़ा सकते हैं।

FILE * के लिए, shared_ptr को एक ही उद्देश्य के लिए वैकल्पिक सूचक के रूप में उपयोग किया जा सकता है (शायद थोड़ा भारी वजन, लेकिन वीसी -2010 और जी ++ दोनों के लिए अच्छा काम करता है)

shared_ptr fp2 (fopen ("tmp.txt", "w"), [] (FILE * fp) {fclose (fp); डालता है ("बंद फ़ाइल");});





unique-ptr