2012-10-07 13 views
12

मैंने this article लिखा और उस पर कुछ टिप्पणियां मिलीं जो मुझे भ्रमित करती थीं।क्या यह सच है कि एक auto_ptr घोषणा, auto_ptr घोषणा के विपरीत, अच्छी तरह परिभाषित है जब इसका टेम्पलेट प्रकार अपूर्ण प्रकार का है?

यह मूल रूप से करने पर निर्भर करता मेरी T2 केवल टेम्पलेट पैरामीटर के रूप में इस्तेमाल भी देखा है और गलती से निष्कर्ष है कि इसलिए मैं आगे घोषणा के अवसर ले सकता है के लिए कूद गया:

struct T2; 

struct T1 
{ 
    std::auto_ptr<T2> obj; 
}; 

यह यूबी का आह्वान करता है, तो मैं डॉन ' टी एक ही टीयू में कहीं T2 परिभाषित करने के लिए पर जाना है, क्योंकि std::auto_ptr<T2> कॉल delete अपने आंतरिक T2* पर, और calling delete on an pointer to an object of an incomplete type whose complete type has a non-trivial destructor is undefined:

[C++11: 5.3.5/5]: हैं हटाए जाने वाले ऑब्जेक्ट में अपूर्ण वर्ग के प्रकार को अपूर्ण बिंदु पर रखा गया है और पूर्ण वर्ग में एक गैर-तुच्छ विनाशक या एक विलोपन समारोह है, व्यवहार अपरिभाषित है।

टिप्पणी:

जीसीसी toolchain मैं (Sourcery जी ++ लाइट 2009q1-203) — — v4.3.3 का उपयोग किया हुआ मुझे एक नोट के साथ यह बताने के लिए तरह पर्याप्त था न नाशक है और न ही क्लास-विशिष्ट ऑपरेटर डिलीट को कॉल किया जाएगा, भले ही कक्षा को परिभाषित किया गया हो।

हालांकि अन्य जीसीसी संस्करणों में यह निदान प्राप्त करना मुश्किल लगता है।

मेरे चंगुल में यह एक अधूरी प्रकार का एक उदाहरण के लिए सूचक ing अगर delete इस तरह एक बग को पहचानना बहुत आसान होता था रहे थे बीमार का गठन बल्कि यूबी से है, लेकिन उस के लिए एक intractible समस्या की तरह लगता है हल करने के लिए एक कार्यान्वयन, इसलिए मैं समझता हूं कि यह यूबी क्यों है।

लेकिन फिर मुझे बताया गया कि, यदि मैंका उपयोग करना चाहता था, तो यह सुरक्षित और अनुपालनशील होगा।

n3035 कथित तौर पर 20.9.10.2 में कहते हैं:

टेम्पलेट पैरामीटर unique_ptr की T एक अधूरी प्रकार हो सकता है।

सभी मैं सी ++ 11 उचित में मिल सकती है:

[C++11: 20.7.1.1.1]:

/1default_delete वर्ग टेम्पलेट के लिए डिफ़ॉल्ट Deleter (विनाश नीति) के रूप में कार्य वर्ग टेम्पलेट unique_ptr

/2 टेम्पलेट पैरामीटर default_delete की T एक अधूरी प्रकार हो सकता है।

[C++11: 20.7.1.1.2/4]: तो T एक अधूरी प्रकार है, कार्यक्रम बीमार बनाई है:

लेकिन, default_delete के operator() एक पूरा प्रकार की आवश्यकता है।


मुझे लगता है मेरे सवाल यह है:

मेरे लेख पर टिप्पणी करने वालों का कहना है कि एक अनुवाद केवल निम्न कोड से मिलकर इकाई अच्छी तरह से बनाई है और अच्छी तरह से परिभाषित में सही हैं? या वे गलत हैं?

struct T2; 

struct T1 
{ 
    std::unique_ptr<T2> obj; 
}; 

वे सही, कैसे एक संकलक यह लागू होने की उम्मीद है रहे हैं, तो दिए गए वहाँ यूबी किया जा रहा है इसके लिए अच्छा कारण हैं कि, कम से कम एक std::auto_ptr प्रयोग किया जाता है जब?

+0

क्योंकि शब्द 'कार्यक्रम खराब है' (बिना किसी स्पष्ट 'और कोई निदान की आवश्यकता है') और उदा। 'इसका परिणाम अपरिभाषित व्यवहार में होता है', यह * का मतलब है कि एक निदान की आवश्यकता है (जिसे 'static_assert (sizeof (टी)," ") के रूप में कार्यान्वित किया जा सकता है।)। तो हाँ, 'std :: unique_ptr ' std :: auto_ptr 'से सुरक्षित है। (लेकिन ध्यान दें कि डिफ़ॉल्ट 'std :: default_delete 'डिलीटर के उपयोग के कारण है। –

+1

मैं यह स्पष्ट करना चाहता था कि' कोड अच्छी तरह से गठित और अच्छी तरह से परिभाषित '/' यूबी 'नहीं है' केवल दो संभावित परिणाम नहीं। (ऐसा नहीं हो सकता है कि आप जो व्यक्त करना चाहते थे, लेकिन मैं स्पष्ट होना चाहूंगा।) –

उत्तर

9

GOTW #100 में हर्ब Sutter, अपूर्ण प्रकार के संबंध में auto_ptr के रूप में एक ही समस्या से ग्रस्त unique_ptr के अनुसार।

... हालांकि दोनों unique_ptr और shared_ptr एक अधूरा प्रकार के साथ instantiated जा सकता है, unique_ptr नाशक आदेश को हटा आह्वान करने के लिए में एक पूरा प्रकार की आवश्यकता है ...

उनका यह सुझाव घोषित करने के लिए है हेडर फ़ाइल में अपनी युक्त कक्षा (यानी T1) का विनाशक, फिर इसकी परिभाषा को एक अनुवाद इकाई में रखें जिसमें T2 एक पूर्ण प्रकार है।

// T1.h 
struct T2; 

struct T1 
{ 
    ~T1(); 
    std::unique_ptr<T2>; 
}; 

// T1.cpp 
#include "T2.h" 

T1::~T1() 
{ 
} 
+1

केवल 'std :: unique_ptr ' इस संपत्ति में, 'std :: unique_ptr' पूरी तरह से नहीं है, और मैं इसे एक समस्या नहीं कहूंगा । यदि आप टाइप-एरर की लागत का भुगतान करने के ठीक हैं तो आप उदा। एक 'std :: unique_ptr <टी, std :: function >' और निर्माण समय पर उचित डिलीटर पास करें। –

+0

एक विकल्प 'std :: unique_ptr <टी, शून्य (*) (टी *)>' (उदाहरण के साथ एक कैप्चर-कम लैम्ब्डा के साथ) जहां लागत एक संकेत है। –

8

निम्न उदाहरण std::auto_ptr<T> और std::unique_ptr<T> के बीच अंतर को प्रदर्शित करने का प्रयास है। पहले 2 स्रोत फ़ाइलें और 1 हैडर से मिलकर इस कार्यक्रम पर विचार करें:

हैडर:

// test.h 

#ifndef TEST_H 
#define TEST_H 

#include <memory> 

template <class T> 
using smart_ptr = std::auto_ptr<T>; 

struct T2; 

struct T1 
{ 
    smart_ptr<T2> obj; 

    T1(T2* p); 
}; 

T2* 
source(); 

#endif // TEST_H 

पहले स्रोत:

// test.cpp 

#include "test.h" 

int main() 
{ 
    T1 t1(source()); 
} 

दूसरा स्रोत:

// test2.cpp 

#include "test.h" 
#include <iostream> 


struct T2 
{ 
    ~T2() {std::cout << "~T2()\n";} 
}; 

T1::T1(T2* p) 
    : obj(p) 
{ 
} 

T2* 
source() 
{ 
    return new T2; 
} 

इस कार्यक्रम चाहिए संकलित करें (यह एक चेतावनी के साथ संकलित हो सकता है, लेकिन इसे संकलित करना चाहिए)। लेकिन रन टाइम पर यह अनिर्धारित व्यवहार का प्रदर्शन करता है।

~T2() 

जो इंगित करता है कि T2 के नाशक चलाया गया नहीं किया: और यह शायद उत्पादन नहीं होगा। कम से कम यह मेरे सिस्टम पर नहीं है।

अगर मैं करने के लिए test.h बदलने के लिए:

template <class T> 
using smart_ptr = std::unique_ptr<T>; 

फिर संकलक उत्पादन के लिए एक निदान (एक त्रुटि) की आवश्यकता है।

यही है, जब आप auto_ptr के साथ यह गलती करते हैं तो आपको रन टाइम त्रुटि मिलती है। जब आप unique_ptr के साथ यह गलती करते हैं तो आपको संकलन समय त्रुटि मिलती है। और किauto_ptr और unique_ptr के बीच अंतर है।

संकलन समय त्रुटि को ठीक करने के लिए आपको T2 के बाद को रेखांकित करना होगा। test2.cpp में T2 के बाद जोड़ें:

T1::~T1() = default; 

अब यह संकलन और उत्पादन करना चाहिए:

~T2() 

आप संभावना घोषित करने और साथ ही रूपरेखा चाल सदस्यों चाहते हैं:

T1::T1(T1&&) = default; 
T1& T1::operator=(T1&&) = default; 

आप auto_ptr के साथ ये वही फिक्स कर सकता है और यह फिर से सही होगा। लेकिन फिर, auto_ptr और unique_ptr के बीच का अंतर यह है कि पूर्व के साथ, आपको रन टाइम तक पता नहीं चलता है कि आपके पास कुछ डिबगिंग है (मॉड्यूल वैकल्पिक चेतावनियां आपके कंपाइलर दे सकती हैं)। उत्तरार्द्ध के साथ आप संकलन समय पर पता लगाने की गारंटी दी जाती है।

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