2015-06-05 1 views
13

मुझे एक टेस्ट केस मिला है जहां मेरे पास 3 सबोबजेक्ट्स (A, B और C) के साथ एक कक्षा है, और दूसरा सबोबजेक्ट B निर्माण के दौरान अपवाद फेंकता है। जैसा कि मैं सी ++ को समझता हूं, संकलक को बड़ी कक्षा के निर्माण को रिवाइंड करना चाहिए और पहली वस्तु A को नष्ट करना चाहिए, लेकिन दूसरा (B) या तीसरा (C) ऑब्जेक्ट्स नहीं।इंटेल 2015 कंपाइलर बग, आरएआईआई विनाश सही नहीं है, क्या यह एक बग है या क्या मैं कुछ गलत कर रहा हूं?

क्या मैं देख रहा हूँ कि अगर मैं पहली वस्तु A की "इन-वर्ग प्रारंभ", तो बजाय पहली वस्तु A का उपयोग को नष्ट कर दिया हो रही है, 3 वस्तु C नष्ट हो जाता है। बेशक यह बहुत खराब है जो किसी ऑब्जेक्ट को नष्ट करने के लिए नहीं बनाया गया है! यदि, उदाहरण के लिए, Cstd:unique_ptr<T> था, तो यह संभवतः एक कचरा संकेतक सिग्नल करेगा जब यह कचरा सूचक को मुक्त करने का प्रयास करता है।

यदि मैं पुराने स्कूल "सदस्य प्रारंभिकरण" का उपयोग करता हूं, तो यह समस्या नहीं होती है।

मैं कोड यह जीसीसी 4.8

के साथ इस दिखाई नहीं देता। वर्ग D बग का खुलासा करता है। कक्षा E में समान कार्य होना चाहिए, लेकिन यह बग का पर्दाफाश नहीं करता है।

#include <iostream> 

using namespace std; 


struct A { 
    A(const string& x) : x_(x) { cout << "A::A()" << (void*)this <<endl; } 
    ~A() { cout << "A::~A() " << (void*)this<< endl;} 
    string x_; 
}; 

struct B { 
    B(const A& a) { cout << "B::B()" << endl; throw "dead"; } 
    ~B() { cout << "B::~B()" << endl;} 
}; 

struct C { 
    C() { cout << "C::C()" << endl; } 
    ~C() { cout << "C::~C()" << endl;} 
}; 


struct D { 
    A a{"foo"}; // "new school In-class initialization" 
    B b{a}; 
    C c; 
    D() { cout <<"D::D()" << endl; } 
    ~D() { cout <<"D::~D()" << endl; } 
}; 

struct E { 
    A a; 
    B b; 
    C c; 
    E() 
     :a{"foo"} // "old school member initialization" 
     ,b(a) 
     { cout <<"E::E()" << endl; } 
    ~E() { cout <<"E::~E()" << endl; } 
}; 

int main() 
{ 
    try { 
     D d; 
    } 
    catch(...) 
    { 
     cout << "got exception" << endl; 
    } 

    try { 
     E e; 
    } 
    catch(...) 
    { 
     cout << "got exception" << endl; 
    } 

    return 0; 
} 

यहां आउटपुट है। मुझे A का निर्माण करने की उम्मीद है, B आंशिक रूप से निर्मित तब फेंकता है, फिर A नष्ट हो गया, लेकिन यह D मामले के लिए मैं नहीं देखता हूं।

$ icpc -std=c++11 test.cpp 
$ ./a.out 
A::A()0x7fffe0a5ee90 
B::B() 
C::~C() 
got exception 

A::A()0x7fffe0a5eea0 
B::B() 
A::~A() 0x7fffe0a5eea0 
got exception 

- अद्यतन -

standard का वर्णन करता है कि क्या होना चाहिए की धारा 15.2.3

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

+0

उन है कि रुचि रखते हैं के लिए, एक 'कोशिश/catch' आवरण की उपस्थिति स्टैक में एक फर्क नहीं पड़ता और वहाँ compilers में विसंगतियों हैं: http://stackoverflow.com/questions/22137693/ देखना अगर-प्रारंभिक-या-विनाश-समाप्त हो गया है-अपवाद-जो-हाथ नहीं है –

उत्तर

4

यह निश्चित रूप से एक कंपाइलर बग है, और आपने मानक से सही संदर्भ के साथ अपने स्वयं के प्रश्न का उत्तर दिया है: [को छोड़कर।ctor]/3, अतिरिक्त बल के साथ:

किसी भी भंडारण अवधि जिसका प्रारंभ या विनाश एक अपवाद द्वारा समाप्त होता है के वर्ग प्रकार का ऑब्जेक्ट के लिए, नाशक वस्तु की पूरी तरह से निर्माण किया subobjects से प्रत्येक के लिए शुरू हो जाती है , अर्थात, प्रत्येक सबोबजेक्ट के लिए जिसके लिए प्रिंसिपल कन्स्ट्रक्टर (12.6.2) ने निष्पादन निष्पादन पूरा कर लिया है और विनाशक अभी तक निष्पादन शुरू नहीं हुआ है, सिवाय इसके कि विनाश के मामले में, यूनियन जैसी कक्षा के संस्करण सदस्य नष्ट नहीं हैं। उपनिवेश उनके निर्माण के पूरा होने के विपरीत क्रम में नष्ट हो जाते हैं। इस तरह के विनाश को कन्स्ट्रक्टर या विनाशक के कार्य-प्रयास-ब्लॉक के हैंडलर में प्रवेश करने से पहले अनुक्रमित किया जाता है, यदि कोई हो।

कहाँ:

प्रमुख निर्माता पहले निर्माता है एक वस्तु के निर्माण में लागू (कि उस वस्तु के निर्माण के लिए है, न कि लक्ष्य निर्माता है)।

C पूरी तरह से निर्मित नहीं किया गया है - इसके मुख्य निर्माता को अभी तक नहीं कहा गया है - इसलिए यह विनाशक अभी तक नहीं बुलाया जाना चाहिए।

+0

मुझे चिंता थी कि मैंने कुछ बेवकूफ किया, जिसके कारण यूबी उत्पन्न हुई, जिसके बाद सभी दांव बंद हो गए। –

+0

@ मार्ककाकाटा सब कुछ जो मैं बता सकता हूं उससे बिल्कुल उचित दिखता है। – Barry

1

इंटेल ने पुष्टि की है कि यह एक मुद्दा है।

संकलक मैं इस्तेमाल किया

icpc (ICC) 15.0.2 20150121 

आप जब यह हल हो गई है पर जानकारी के लिए इंटेल मंच का पालन कर सकते थे।

https://software.intel.com/en-us/comment/1827356

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