2010-01-06 16 views
9

मान लीजिए मैंक्या खाली कक्षा के निर्माता को वास्तव में किसी भी स्मृति का उपयोग करना है?

class Empty{ 
    Empty(int a){ cout << a; } 
} 

की तरह एक वर्ग है और फिर मैं यह

int main(){ 
    Empty(2); 
    return 0; 
} 

का उपयोग कर लागू करेगा इस कारण किसी भी स्मृति एक "खाली" वस्तु के निर्माण के लिए ढेर पर आवंटित किया जाना? जाहिर है, तर्कों को ढेर पर धकेलने की जरूरत है, लेकिन मैं कोई अतिरिक्त ओवरहेड नहीं लेना चाहता हूं। असल में मैं एक स्थिर सदस्य के रूप में निर्माता का उपयोग कर रहा हूँ।

कारण मैं टेम्पलेट्स के कारण ऐसा करना चाहता हूं।

तरह
template <int which> 
class FuncName{ 
    template <class T> 
    FuncName(const T &value){ 
     if(which == 1){ 
      // specific behavior 
     }else if(which == 2){ 
      // other specific behavior 
     } 
    } 
}; 

जो मुझे,

int main(){ 
    int a = 1; 
    FuncName<1>(a); 
} 
ताकि मैं एक टेम्पलेट पैरामीटर विशेषज्ञ करने के लिए मिलता

की तरह कुछ लिखने के लिए है, जबकि T का प्रकार निर्दिष्ट करने नहीं होने की अनुमति देता है वास्तविक कोड लग रहा है। साथ ही, मुझे आशा है कि संकलक अन्य शाखाओं को कन्स्ट्रक्टर के अंदर दूर कर देगा। अगर कोई जानता है कि यह सच है या कैसे जांचें, तो इसकी सराहना की जाएगी। मैंने यह भी माना कि स्थिति में टेम्पलेट फेंकने से ऊपर से "खाली वर्ग" समस्या नहीं बदली है, क्या यह सही है?

+0

सवाल यह है कि आप परवाह क्यों करते हैं।यह सबसे अच्छा कोड की देखभाल और उत्पन्न करने के लिए कंपाइलर का काम है। आपको सबसे अभिव्यक्ति कोड लिखने पर ध्यान देना चाहिए। –

+0

पीएस। स्टैक पर तर्क को धक्का देने की कोई आवश्यकता नहीं है। सी ++ एबीआई को जानबूझकर परिभाषित नहीं किया गया है ताकि कंप्यूटर्स के पास पैरामीटर पास करने के लिए रजिस्टर का उपयोग करने के लिए ऑपरेशन हो, यदि कोड को अधिक प्रभावशाली बनाता है –

+0

मुझे परवाह है क्योंकि मैं उच्चतम प्रदर्शन प्राप्त कर सकता हूं; मैं वास्तव में इस दृष्टिकोण से नफरत करता हूं कि कोड सुरुचिपूर्ण होना चाहिए और इन चीजों के बारे में चिंता न करें। कभी-कभी, ये चीजें मायने रखती हैं (मैं उच्च प्रदर्शन कंप्यूटिंग करता हूं)। –

उत्तर

16

Stroustrup का हवाला देते हुए:

एक खाली वर्ग के आकार क्यों शून्य नहीं है? यह सुनिश्चित करने के लिए कि दो अलग-अलग वस्तुओं के पते अलग होंगे। इसी कारण से, "नया" हमेशा विशिष्ट वस्तुओं को पॉइंटर्स देता है। पर विचार करें:

class Empty { }; 

void f() 
{ 
    Empty a, b; 
    if (&a == &b) cout << "impossible: report error to compiler supplier"; 

    Empty* p1 = new Empty; 
    Empty* p2 = new Empty; 
    if (p1 == p2) cout << "impossible: report error to compiler supplier"; 
} 

एक दिलचस्प शासन का कहना है कि एक खाली आधार वर्ग एक अलग बाइट द्वारा प्रतिनिधित्व करने की आवश्यकता नहीं है:

struct X : Empty { 
    int a; 
    // ... 
}; 

void f(X* p) 
{ 
    void* p1 = p; 
    void* p2 = &p->a; 
    if (p1 == p2) cout << "nice: good optimizer"; 
} 

यह अनुकूलन सुरक्षित है और सबसे अधिक उपयोगी हो सकता है। यह एक प्रोग्रामर को बिना खाली के बहुत सरल अवधारणाओं का प्रतिनिधित्व करने के लिए खाली कक्षाओं का उपयोग करने की अनुमति देता है। कुछ वर्तमान कंपाइलर इस "खाली बेस क्लास अनुकूलन" प्रदान करते हैं।

+0

लेकिन क्या हुआ अगर ऑब्जेक्ट बनाया गया तो कभी भी संदर्भित नहीं किया जाता है? क्या संकलक को इसके लिए कोई स्टैक स्पेस आरक्षित करने की इजाजत नहीं है, या इसे तुरंत साफ कर दिया गया है, भले ही यह दायरे से बाहर न हो? –

+0

हां, मुझे यकीन है कि एक कंपाइलर आरक्षित मेमोरी को पूरी तरह खत्म कर देगा अगर इसका उपयोग नहीं किया जाता है या संदर्भित किया जाता है। यह एक बहुत ही सरल अनुकूलन है। निश्चित रूप से कंपाइलर के आधार पर। –

+1

जब तक व्यवहार परिवर्तित नहीं होता है तब तक संकलक हुड के नीचे वस्तु की पूरी अवधारणा को खत्म करने के लिए स्वतंत्र होता है और पूरी चीज को कोड में और रजिस्टरों में संग्रहीत सभी मूल्यों में रेखांकित किया जा सकता है। –

2

यह परिस्थितियों के आधार पर हो सकता है, ऐसा नहीं हो सकता है। यदि आप कहते हैं:

Empty e; 
Empty * ep = & e; 

तो स्पष्ट रूप से चीजों को आवंटित किया जाना चाहिए।

+0

क्या संकलक को यद्यपि इसे एक पते देने के लिए कोड _allocate_ को उत्सर्जित करना होगा? क्या कोई कारण नहीं है कि ई कोई ऐसा पता नहीं हो सकता है जो न तो ढेर और न ही ढेर हो, और जहां कोई वास्तविक वस्तु नहीं है? – James

+0

@Autopulated: मुझे विश्वास है, रिचर्ड पेनिंगटन की टिप्पणी देखें। अधिक दिलचस्प सवाल यह है कि यदि आप कभी भी इसके पते के लिए नहीं पूछते हैं; तो क्या यह अभी भी एक है? (एक बहुत ज़ेन-जैसा सवाल) –

+1

यदि आप ई का पता लेते हैं, और उसके बाद उस पते के साथ कुछ करें (जो मेरा उदाहरण कोड नहीं करता है) तो ई को तुरंत चालू किया जाना चाहिए - यानी आवंटित किया जाना चाहिए। –

2

इसे आज़माएं और देखें। जब उनके आउटपुट को अनुकूलित करने के लिए कहा जाता है तो कई कंपाइलर्स ऐसी अस्थायी वस्तुओं को खत्म कर देंगे।

हैं disassembly बहुत जटिल है, तो इस तरह की वस्तुओं के विभिन्न संख्या के साथ दो कार्यों की तरह कुछ बना सकते हैं और अगर वहाँ उन्हें आसपास के वस्तुओं के ढेर स्थानों में कोई अंतर है देखते हैं,:

void empty1 (int x) 
{ 
    using namespace std; 

    int a; 
    Empty e1 (x); 
    int b; 

    cout << endl; 
    cout << "empty1" << endl; 
    cout << hex << int (&x) << " " << dec << (&x - &a) << endl; 
    cout << hex << int (&a) << " " << dec << (&a - &b) << endl; 
} 

और फिर कोशिश चल रहे आठ एम्प्टीज़ के साथ empty8 फ़ंक्शन की तुलना में चल रहा है। X86 पर g ++ के साथ, यदि आप किसी भी खाली खालीियों का पता लेते हैं तो आपको एक्स और ए के बीच एक स्थान मिलता है, इसलिए आउटपुट में एक्स भी शामिल है। आप यह नहीं मान सकते कि ऑब्जेक्ट्स के लिए स्टोरेज उसी क्रम में समाप्त हो जाएगा जैसा कि उन्हें स्रोत कोड में घोषित किया गया है।

+0

कैसे? मैं एक साधारण उदाहरण के लिए g ++ असेंबली सूची देख रहा हूं और इसका पालन करना बहुत मुश्किल है। मैं 'g ++ -c -g -O2 -Wa, -ahl = file.s file.cpp' –

+0

का उपयोग कर रहा हूं, आप निष्पादन योग्य (डीबग जानकारी के साथ) को बेहतर संकलित कर सकते हैं, फिर 'objdump -dS' का उपयोग करें, और उन स्रोत लाइनों की खोज करें जिनमें आप रुचि रखते हैं। चूंकि आपके पास अनुकूलन है, याद रखें कि उसी स्रोत रेखा को अलग-अलग स्थानों में दिखाई देने के लिए उत्तरदायी है। –

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

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