2013-06-08 6 views
5

क्या यह कानूनी C++ 11 में है? नवीनतम इंटेल कंपाइलर के साथ संकलित करता है और काम करता प्रतीत होता है, लेकिन मुझे लगता है कि यह एक झलक है।टेम्पलेट आकार के आधार पर नया प्लेसमेंट()

class cbase 
     { 
     virtual void call(); 
     }; 

template<typename T> class functor : public cbase 
    { 
    public: 
     functor(T* obj, void (T::*pfunc)()) 
      : _obj(obj), _pfunc(pfunc) {} 

     virtual void call() 
      { 
      (_obj)(*_pfunc)(); 
      } 
    private: 
     T& _obj; 
     void (T::*_pfunc)();    
     //edited: this is no good: 
     //const static int size = sizeof(_obj) + sizeof(_pfunc); 
    }; 

class signal 
    { 
    public: 
     template<typename T> void connect(T& obj, void (T::*pfunc)()) 
      { 
      _ptr = new (space) functor<T>(obj, pfunc); 
      } 
    private: 
     cbase* _ptr; 
     class _generic_object {}; 
     typename aligned_storage<sizeof(functor<_generic_object>), 
      alignment_of<functor<_generic_object>>::value>::type space; 
     //edited: this is no good: 
     //void* space[(c1<_generic_object>::size/sizeof(void*))]; 

    }; 

विशेष रूप से मैं अगर void* space[(c1<_generic_object>::size/sizeof(void*))]; वास्तव में c1 के सदस्य वस्तुओं (_obj और _pfunc) के लिए सही आकार देने के लिए जा रहा है सोच रहा हूँ। (यह नहीं है)।

संपादित करें: तो कुछ और अधिक शोध के बाद यह प्रतीत होता है कि निम्नलिखित होगा (अधिक?) सही:

typename aligned_storage<sizeof(c1<_generic_object>), 
    alignment_of<c1<_generic_object>>::value>::type space; 

हालांकि बाधित करने के लिए लगता है उत्पन्न विधानसभा निरीक्षण, प्लेसमेंट नई उपयोग करते हुए इस स्थान के साथ पर दूर 'नए' (करने के लिए कॉल के अनुकूलन से संकलक जो बस नियमित उपयोग करते समय होने के लिए लग रहा था '_ptr = नए c1,'

EDIT2: बदली गई इरादों एक छोटे से स्पष्ट करने के कोड

+0

'c1' में किसी संदर्भ सदस्य के लिए प्रारंभकर्ता प्रदान किए बिना संकलित करना भी कैसा है? क्या उस संदर्भ सदस्य में कोई विशिष्ट महत्व है या नहीं? – AnT

+0

इसके अलावा, 'sizeof (_obj)' के माध्यम से मेमोरी आकार की गणना करने के पीछे विचार क्या है, जो पूर्ण ऑब्जेक्ट (यानी 'आकार का टी') के आकार का मूल्यांकन करता है, फिर भी उस स्थान पर 'c1 ' ऑब्जेक्ट का निर्माण करेगा, जो शारीरिक रूप से केवल कुछ * संदर्भ * को 'some_type_t' (एक सूचक के रूप में कार्यान्वित) में शामिल किया गया है? – AnT

+0

मुझे नहीं पता कि यह संकलित करता है या नहीं, यह एक बहुत ही सरल उदाहरण है जिसे मैंने प्रासंगिक भागों में कटौती करने के लिए यहां पोस्ट करने के लिए बनाया है। मैं सिग्नल/कॉलबैक क्लास लिख रहा हूं और यदि संभव हो तो गतिशील स्मृति आवंटन को खत्म करना चाहता हूं। –

उत्तर

3

।सदस्यों के आकारों का योग देगा, लेकिन यह उन सदस्यों वाले वर्ग के आकार के समान नहीं हो सकता है। कंपाइलर सदस्यों के बीच या अंतिम सदस्य के बाद पैडिंग डालने के लिए स्वतंत्र है। इस प्रकार, सदस्यों के आकार को एक साथ जोड़ना सबसे छोटा अनुमान है कि ऑब्जेक्ट संभवतः हो सकता है, लेकिन आवश्यक रूप से उन सदस्यों के साथ किसी ऑब्जेक्ट का आकार नहीं देता है।

वास्तव में, किसी वस्तु का आकार न केवल अपने सदस्यों के प्रकारों पर निर्भर करता है, बल्कि उनके आदेश पर भी भिन्न हो सकता है।

struct A { 
    int a; 
    char b; 
}; 

बनाम: उदाहरण के लिए:

struct B { 
    char b; 
    int a; 
}; 

कई मामलों में, AB की तुलना में छोटे हो जाएगा। A में, आमतौर पर a और b के बीच कोई पैडिंग नहीं होगी, लेकिन B में, अक्सर कुछ पैडिंग (उदाहरण के लिए, 4-बाइट int के साथ, b और a के बीच अक्सर पैडिंग के 3 बाइट होंगे)।

इस प्रकार, आपके space में उस वस्तु को पकड़ने के लिए पर्याप्त स्थान नहीं हो सकता है जिसे आप init में बनाने की कोशिश कर रहे हैं।

+0

यह एक अच्छा मुद्दा है। आदर्श रूप में मैं ऑब्जेक्ट्स को सी 2 में सीधे स्टोर कर सकता था, लेकिन चूंकि मुझे कोई सदस्य फ़ंक्शन नहीं होने तक टी नहीं पता है, ऐसा लगता है कि ऐसा नहीं लगता है। –

1

मुझे लगता है कि आप अभी भाग्यशाली हैं; जैरी का जवाब बताता है कि पैडिंग मुद्दे हो सकते हैं। मुझे लगता है कि आपके पास एक गैर वर्चुअल क्लास है (यानी, कोई vtable), अनिवार्य रूप से दो पॉइंटर्स (हुड के नीचे) के साथ।

कि एक तरफ, गणित: (c1<_generic_object>::size/sizeof(void*)) से दोषपूर्ण है अगर sizeनहींsizeof(void *) की एक बहु है, क्योंकि यह काटना होगा। ,

((c1<_generic_object>::size + sizeof(void *) - 1)/sizeof(void *))

1

इस कोड को भी गद्दी मुद्दों के लिए नहीं मिलता है, क्योंकि यह अधिक तत्काल लोगों के कुछ है: आप की तरह कुछ की आवश्यकता होगी।

टेम्पलेट वर्ग c1 संदर्भ प्रकार के सदस्य T &_obj को परिभाषित करने के लिए परिभाषित किया गया है। से _objc1 के दायरे में T के आकार का मूल्यांकन करेगा, न कि संदर्भ सदस्य के आकार के लिए।सी ++ (कम से कम सीधे) में संदर्भ के भौतिक आकार को प्राप्त करना संभव नहीं है। इस बीच, c1<T> प्रकार की वास्तविक वस्तु में भौतिक रूप से T का संदर्भ होगा, जिसे आम तौर पर ऐसे मामलों में "हुड के नीचे" सूचक के रूप में लागू किया जाता है।

इस कारण से यह पूरी तरह से मेरे लिए स्पष्ट नहीं है क्यों c1<_generic_object>::size का मूल्य स्मृति का एक उपाय प्रकार c1<T> (किसी भी T के लिए) का एक वास्तविक वस्तु की इन-गति निर्माण के लिए आवश्यक के रूप में प्रयोग किया जाता है के लिए

। यह सिर्फ कोई समझ नहीं आता है। ये आकार बिल्कुल संबंधित नहीं हैं।

शुद्ध भाग्य से रिक्त वर्ग _generic_object का आकार संदर्भ सदस्य के भौतिक कार्यान्वयन के आकार के समान (या अधिक) मान का मूल्यांकन कर सकता है। उस स्थिति में कोड पर्याप्त मात्रा में स्मृति आवंटित करेगा। कोई भी दावा कर सकता है कि sizeof(_generic_object) == sizeof(void *) समानता "आमतौर पर" अभ्यास में रहती है। लेकिन यह किसी भी सार्थक आधार के साथ एक पूरी तरह से मनमाना संयोग होगा।

यह लाल हेरिंग को जानबूझकर शुद्ध obfuscation के उद्देश्य के लिए कोड में डाला गया लगता है।

पीएस एक खाली कक्षा के जीसीसी sizeof में वास्तव में 1 का मूल्यांकन होता है, न कि किसी भी "गठबंधन" आकार के लिए। जिसका अर्थ है कि उपर्युक्त तकनीक c1<_generic_object>::size को बहुत कम मान के साथ शुरू करने की गारंटी है। अधिक विशेष रूप से, 32 बिट जीसीसी में c1<_generic_object>::size का मान 9 होगा, जबकि c1<some_type_t> का वास्तविक आकार 12 बाइट होगा।

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