2010-10-26 19 views
5

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

//First just forward dclr 
#include "stdafx.h" 
#include <iostream> 
using std::cout; 

struct Guest; 

struct Base 
{ 
    Guest* ptr_; 
    Base(Guest* ptr):ptr_(ptr) 
    { 
     cout << "Base\n"; 
    } 
    ~Base() 
    { 
     cout << "~Base\n"; 
     delete ptr_; 
    } 
}; 

struct Guest 
{ 
    Guest() 
    { 
     cout << "Guest\n"; 
     throw std::exception(); 
    } 
    Guest(int) 
    { 
     cout << "Guest(int)\n"; 
    } 
    ~Guest() 
    { 
     cout << "~Guest\n"; 
    } 
}; 

struct MyClass : Base 
{ 
    Guest g; 
    MyClass(Guest* g):Base(g) 
    { 
     cout << "MyClass\n"; 

    } 
    ~MyClass() 
    { 
     cout << "~MyClass\n"; 
    } 
}; 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    try 
    { 
     Guest* g = new Guest(1); 
    MyClass mc(g); 
    } 
    catch(const std::exception& e) 
    { 
     std::cerr << e.what(); 
    } 
    return 0; 
} 

// दूसरा - पूर्ण डीईएफ़

#include "stdafx.h" 
#include <iostream> 
using std::cout; 

struct Guest 
{ 
    Guest() 
    { 
     cout << "Guest\n"; 
     throw std::exception(); 
    } 
    Guest(int) 
    { 
     cout << "Guest(int)\n"; 
    } 
    ~Guest() 
    { 
     cout << "~Guest\n"; 
    } 
}; 

struct Base 
{ 
    Guest* ptr_; 
    Base(Guest* ptr):ptr_(ptr) 
    { 
     cout << "Base\n"; 
    } 
    ~Base() 
    { 
     cout << "~Base\n"; 
     delete ptr_; 
    } 
}; 



struct MyClass : Base 
{ 
    Guest g; 
    MyClass(Guest* g):Base(g) 
    { 
     cout << "MyClass\n"; 

    } 
    ~MyClass() 
    { 
     cout << "~MyClass\n"; 
    } 
}; 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    try 
    { 
     Guest* g = new Guest(1); 
    MyClass mc(g); 
    } 
    catch(const std::exception& e) 
    { 
     std::cerr << e.what(); 
    } 
    return 0; 
} 
+0

आपको दोनों मामलों में अपने बेस क्लास कन्स्ट्रक्टर वर्चुअल बनाना चाहिए। –

+0

@ Space_C0wb0y: प्रिय, आप सी ++ में कन्स्ट्रक्टर वर्चुअल नहीं बना सकते हैं :) –

+0

@ आर्मेन: शब्द ... धूम्रपान और दर्पण। यह मेरे दिमाग में इतना स्पष्ट था। (उन लोगों के लिए जो आश्चर्य करते हैं, यह * विनाशक * होना चाहिए) –

उत्तर

3

अनौपचारिक रूप से: संकलक को ऑब्जेक्ट को सही तरीके से हटाने के लिए कक्षा परिभाषा की आवश्यकता होती है, क्योंकि उसे उस वर्ग के लिए विनाशक और/या operator delete को कॉल करने का तरीका पता होना चाहिए।

औपचारिक रूप से

, 5.3.5/5:

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

आप ठीक होंगे अगर (उदाहरण के लिए) Guest पीओडी था, लेकिन आपने इसे विनाशक दिया, तो आप ठीक नहीं हैं।

3

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

+0

घोषणा -> परिभाषा :) –

+0

नहीं, एक घोषणा पर्याप्त है। हालांकि, एक आगे की घोषणा नहीं होगी। –

+0

@ कोटिंस्की - 'कक्षा एक्स {शून्य एफ(); }; 'यह एक्स की परिभाषा है जबकि' कक्षा एक्स; 'घोषणा –

16

C++ से मानक (5.3.5/5):

वस्तु हटाया जा रहा है, तो हटाए जाने के बिंदु पर अधूरा वर्ग प्रकार है और पूरी कक्षा एक गैर तुच्छ नाशक या आवंटन रद्द कार्य है , व्यवहार अपरिभाषित है।

तो आप अपने अपूर्ण प्रकार पर डिलीट का उपयोग नहीं कर सकते हैं। यह विनाशक को कॉल करेगा और संकलक अभी तक इसके बारे में पता नहीं है।

3

आप एक अपूर्ण प्रकार के लिए सूचक को हटा नहीं सकते हैं। हटाएं उन परिचालनों में से एक है जिसके लिए प्रकार को पूरा करने की आवश्यकता होती है। एचटीएच

2

ptr_ का प्रकार अधूरा है जब आप delete पर इसका आह्वान करते हैं। यह अपरिभाषित व्यवहार की ओर जाता है। तो आपके विनाशक को बुलाया नहीं जा सकता है। आप ऐसे परिदृश्यों से बचने के लिए Boost.checked_delete का उपयोग कर सकते हैं।

2

(। Stdafx.h हैडर मानक C++ नहीं है) अगर मैं जी के साथ संकलन ++ संकलक उत्पन्न करता है:

warning: possible problem detected in invocation of delete operator: 
warning: invalid use of incomplete type ‘struct Guest’ 
warning: forward declaration of ‘struct Guest’ 
note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined. 

अपने संकलक कॉन्फ़िगर उचित चेतावनी और त्रुटि के स्तर पर संकलित करने के लिए।

+1

int _tmain (int argc, _TCHAR * argv []) <- यह मानक भी नहीं है –

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