2012-07-01 19 views
7

मैं यह जानना चाहता हूं कि मेरी फेंक ऑब्जेक्ट स्मृति में संग्रहीत है। तो मैं इसके लिए एक छोटे से कार्यक्रम ने लिखा है:सी ++ में फेंक दिया गया ऑब्जेक्ट कहां है?

#include <iostream> 

#define print_dist() int a;\ 
    do { std::cout << __FUNCTION__ << "() a[" << (long)&a - (long)ptrMainStackBase << "]" << std::endl; } while (0) 

#define print_distx(x) \ 
    do { std::cout << __FUNCTION__ << "() " #x "[" << (long)&x - (long)ptrMainStackBase << "]" << std::endl; } while (0) 

#define print_distxy(x, y) \ 
    do { std::cout << __FUNCTION__ << "() " #x "(ex)[" << (long)&x - (long)y << "]" << std::endl; } while (0) 

class CTest 
{ 
    public: 
     CTest() 
     { std::cout << "CTest::CTest" << std::endl; } 

// private: 
     CTest(const CTest&) 
     { std::cout << "copy" << std::endl; } 
}; 
const CTest *ptrException; 
int *ptrMainStackBase; 

void Test2() 
{ 
    print_dist(); 
    CTest test; 
    print_distx(test); 
    std::cout << "&test=" << &test << std::endl; 
    throw test; 
} 

void Test1() 
{ 
    print_dist(); 
    try 
    { 
     Test2(); 
    } 
    catch (const CTest& test) 
    { 
     ptrException = &test; 
     print_dist(); 
     print_distx(test); 
     print_distxy(test, ptrException); 
     std::cout << "&test=" << &test << std::endl; 
     throw test; 
    } 
} 

int main() 
{ 
    int b; 
    ptrMainStackBase = &b; 
    print_dist(); 
    try 
    { 
     print_dist(); 
     Test1(); 
    } 
    catch (const CTest& test) 
    { 
     print_dist(); 
     print_distx(test); 
     print_distxy(test, ptrException); 
     std::cout << "&test=" << &test << std::endl; 
    } 

    return 0; 
} 

और यह प्रिंट:

main() a[-4] 
main() a[-8] 
Test1() a[-64] 
Test2() a[-104] 
CTest::CTest 
Test2() test[-108] 
&test=0x7fffd3b21628 <- test created here on stack 
copy 
Test1() a[-68] 
Test1() test[-140736732956164] 
Test1() test(ex)[0] 
&test=0xb89090 <- and copied here 
copy 
main() a[-12] 
main() test[-140736732956020] 
main() test(ex)[144] 
&test=0xb89120 <- and here 

ऐसा लगता है, जैसे जब मैं एक वस्तु फेंक, यह पहली एक और ढेर से दूर बहुत दूर है पर कॉपी किया है सामान्य एक क्या ये सच है? और दो "अपवाद स्टैक फ्रेम" के बीच 144 बाइट दूरी क्यों है?

उत्तर

6

जब आप कोई ऑब्जेक्ट फेंकते हैं तो यह वास्तव में कुछ अस्थायी स्थान पर कॉपी किया जाता है। अन्यथा, स्टैक अनोलिंग इसे दायरे से बाहर ले लेती। संदर्भ द्वारा फिर इसे पकड़ने, अपरिभाषित व्यवहार में हुई है | इसलिए की तरह:

void foo() { 
    A a; 
    throw a; 
} 

void bar() { 
    try { 
     foo(); 
    } catch (A& a) { 
     // use a 
    } 
} 

a जब तक कुछ अस्थायी स्थान पर कॉपी किया गया था, आप एक ऐसा वैरिएबल नहीं रह गया है catch में मौजूद है के लिए एक संदर्भ होगा। इसके लिए काम करने के लिए, A में एक सार्वजनिक प्रतिलिपि निर्माता होना चाहिए (जब तक कि आप वीएस का उपयोग नहीं कर रहे हों, उस स्थिति में it will use a private one as well...)। इसके अलावा, संदर्भ द्वारा पकड़ने का यह एक अच्छा कारण है - अन्यथा, आपके पास दो की बजाय दो प्रति निर्माण होंगे।

+0

मुझे विश्वास नहीं है! मुझे लगता है कि संदर्भ द्वारा एक फेंक दिया ऑब्जेक्ट पकड़ना सामान्य है। –

+0

@ औद्योगिक-एंटीड्रिप्रेसेंट, यह है, और यह होना चाहिए - यह तथ्य इस तथ्य के कारण पूरी तरह से सुरक्षित है कि फेंक दिया गया वस्तु कॉपी की गई है। अगर इसकी प्रतिलिपि नहीं बनाई गई तो आपको कोई समस्या होगी। – eran

2

ऐसा लगता है, जैसे जब मैं एक वस्तु फेंक यह एक अन्य ढेर जो अब तक सामान्य से एक से दूर है करने के लिए पहले की नकल की है। क्या ये सच है?

test कि फेंक दिया गया था अस्तित्व में नहीं है जब अपवाद पकड़ा है। वह मूल test पहले से ही नष्ट कर दिया गया है। इसलिए इसे एक प्रतिलिपि बनाना है, और नई वस्तु तर्क और स्थानीय चर से अलग से प्रबंधित की जाती है। दूसरे शब्दों में, ढेर पर नहीं।

यह कहां रहता है? यह कार्यान्वयन पर निर्भर है। सबसे अधिक संभावना है कि यह गतिशील स्मृति (उदाहरण के लिए, ढेर) कि कार्यान्वयन आपके लिए प्रबंधन करता है।

और दो "अपवाद स्टैक फ्रेम" के बीच 144 बाइट दूरी क्यों है?

मानक यह नहीं कहता कि catch ब्लॉक में फिर से फेंकने पर अपवाद का इलाज कैसे किया जाता है। चूंकि स्थानीय चर के throw को एक प्रतिलिपि बनाना आवश्यक है, throw को लागू करने का सबसे आसान तरीका हमेशा एक प्रतिलिपि बनाना है।

+0

यह भी एक बहुत अच्छा जवाब है लेकिन मैं केवल एक का चयन कर सकता हूं –

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