C ++ आपको एक निर्माता का पता लेने की अनुमति क्यों नहीं देता है?


14

क्या कोई विशिष्ट कारण है कि यह भाषा को वैचारिक रूप से तोड़ देगा या एक विशिष्ट कारण है कि यह कुछ मामलों में तकनीकी रूप से प्रभावी है?

उपयोग नए ऑपरेटर के साथ होगा।

संपादित करें: मैं अपने "नए ऑपरेटर" और "ऑपरेटर नए" सीधे होने की उम्मीद छोड़ दूंगा और प्रत्यक्ष हो जाऊंगा।

सवाल का मुद्दा यह है: क्यों निर्माता विशेष हैं ? इस बात का ध्यान रखें कि भाषा के विनिर्देश हमें बताएं कि क्या कानूनी है, लेकिन जरूरी नहीं कि नैतिक हो। कानूनी तौर पर क्या सूचित किया जाता है, जो भाषा के बाकी हिस्सों के साथ तार्किक रूप से सुसंगत है, जो सरल और संक्षिप्त है, और जिसे लागू करने के लिए संकलक के लिए संभव है। इन कारकों को तौलने में मानक समिति का संभावित तर्क जानबूझकर और दिलचस्प है - इसलिए सवाल।


यह किसी कंस्ट्रक्टर का पता लेने की समस्या नहीं होगी, बल्कि प्रकार से गुजरने में सक्षम होगा। टेम्पलेट ऐसा कर सकते हैं।
व्यंग्यात्मक

क्या होगा यदि आपके पास एक फ़ंक्शन टेम्प्लेट है जो आप एक निर्माता का उपयोग करके एक ऑब्जेक्ट का निर्माण करना चाहते हैं जो फ़ंक्शन के तर्क के रूप में निर्दिष्ट किया जाएगा?
प्रिक्सोलिटिक

1
ऐसे किसी भी उदाहरण के लिए विकल्प होंगे, जो मैं सोच सकता हूं, लेकिन फिर भी, कंस्ट्रक्टर विशेष क्यों होना चाहिए? ऐसी बहुत सी चीजें हैं जो आप संभवतः अधिकांश प्रोग्रामिंग भाषाओं में उपयोग नहीं करेंगे लेकिन इस तरह के विशेष मामले आमतौर पर औचित्य के साथ आते हैं।
प्रिक्सोलिटिक

1
@RobertHarvey सवाल मुझसे तब हुआ जब मैं एक फैक्ट्री क्लास टाइप करने वाला था।
प्रेक्सालिटिक

1
मुझे आश्चर्य है कि अगर C ++ 11 std::make_uniqueऔर std::make_sharedइस प्रश्न के लिए अंतर्निहित व्यावहारिक प्रेरणा को पर्याप्त रूप से हल कर सकता है। ये टेम्पलेट विधियां हैं, जिसका अर्थ है कि किसी को निर्माण तर्क को इनपुट तर्कों को पकड़ने की आवश्यकता है, और फिर उन्हें वास्तविक निर्माता को अग्रेषित करें।
rwong

जवाबों:


10

यदि आप एक ही हस्ताक्षर के साथ एक से अधिक सदस्य कार्य करते हैं, तो पॉइंट-टू-मेंबर फ़ंक्शन केवल एक ही अर्थ रखते हैं - अन्यथा आपके पॉइंटर के लिए केवल एक ही संभव मूल्य होगा। लेकिन यह संभव नहीं है कि यह संभव नहीं है, क्योंकि C ++ में एक ही वर्ग के अलग-अलग निर्माणकर्ताओं के अलग-अलग हस्ताक्षर होने चाहिए।

Stroustrup के लिए विकल्प C ++ के लिए एक सिंटैक्स चुनना होगा, जहां कंस्ट्रक्टरों के वर्ग के नाम से अलग नाम हो सकता है - लेकिन इससे मौजूदा ctor सिंटैक्स के कुछ बहुत ही खूबसूरत पहलुओं को रोका जा सकता है और इससे भाषा और अधिक जटिल हो जाएगी। मेरे लिए जो एक उच्च कीमत की तरह दिखता है, शायद ही कभी एक आवश्यक सुविधा की अनुमति देने के लिए जिसे आसानी से "आउटसोर्सिंग" से किसी वस्तु के आरंभीकरण को एक अलग initफ़ंक्शन (एक सामान्य सदस्य फ़ंक्शन जिसके लिए पॉइंटर-टू-मेंबर्स हो सकता है) द्वारा अनुकरण किया जा सकता है बनाया था)।


2
फिर भी, रोकथाम क्यों memcpy(buffer, (&std::string)(int, char), size)? (शायद बेहद अन-कोषेर, लेकिन यह सब के बाद सी ++ है।)
थॉमस ईडिंग

3
क्षमा करें, लेकिन आपने जो लिखा है उसका कोई मतलब नहीं है। मुझे कुछ भी गलत नहीं दिखता है, क्योंकि एक पॉइंटर की ओर इशारा करने वाले सदस्य को पॉइंटर दिया गया है। स्रोत के लिंक के बिना, यह भी लगता है कि आपने कुछ उद्धृत किया है।
B:овиЈ

1
@ThomasEding: क्या आप वास्तव में उस कथन को करने की उम्मीद करते हैं? स्ट्रिंग ctor के असेंबली कोड को कॉपी करना कहीं? "आकार" कैसे निर्धारित किया जाएगा (भले ही आप मानक सदस्य फ़ंक्शन के लिए कुछ समतुल्य प्रयास करें)?
डॉक ब्राउन

मुझे उम्मीद है कि यह वही काम करेगा जो एक फ्री फंक्शन पॉइंटर के पते के रूप में करेगा memcpy(buffer, strlen, size)। शायद यह विधानसभा की नकल करेगा, लेकिन कौन जानता है। दुर्घटनाग्रस्त हुए बिना कोड को लागू किया जा सकता है या नहीं, इसके लिए आपके द्वारा उपयोग किए जाने वाले कंपाइलर के बारे में जानकारी की आवश्यकता होगी। वही आकार निर्धारित करने के लिए जाता है। यह अत्यधिक प्लेटफ़ॉर्म पर निर्भर होगा, लेकिन बहुत सारे गैर-पोर्टेबल सी ++ कंस्ट्रक्शन कोड में उपयोग किए जाते हैं। मुझे इसका कोई कारण नहीं दिखता।
थॉमस ईडिंग

@ThomasEding: एक फंक्शन पॉइंटर को एक्सेस करने की कोशिश करते समय एक कन्फर्मिंग सी ++ कंपाइलर एक डायग्नोस्टिक देने की उम्मीद करता है, जैसे कि वह डेटा पॉइंटर था। एक गैर-अनुरूपता सी ++ संकलक कुछ भी कर सकता था, लेकिन वे एक निर्माता के रूप में भी एक्सेस करने का एक गैर-सी ++ तरीका प्रदान कर सकते हैं। यह C ++ में एक सुविधा जोड़ने का एक कारण नहीं है जिसका अनुरूप कोड में कोई उपयोग नहीं है।
बार्ट वैन इनगेन शेनौ

5

एक कंस्ट्रक्टर एक फ़ंक्शन है जिसे आप तब कॉल करते हैं जब ऑब्जेक्ट अभी तक मौजूद नहीं है, इसलिए यह सदस्य फ़ंक्शन नहीं हो सकता है। यह स्थिर हो सकता है।

एक निर्माता को वास्तव में इस पॉइंटर के साथ बुलाया जाता है, मेमोरी आवंटित होने के बाद लेकिन इससे पहले कि यह पूरी तरह से शुरू हो गया हो। परिणामस्वरूप एक कंस्ट्रक्टर के पास कई विशेषाधिकार प्राप्त विशेषताएं हैं।

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

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

यदि आप केवल सामान्य आरंभीकरण कोड को बाहर निकालना चाहते हैं तो एक साधारण मेमोरी फ़ंक्शन आमतौर पर एक पर्याप्त उत्तर है, और आप उनमें से एक को एक पॉइंटर प्राप्त कर सकते हैं।


यह सबसे सही उत्तर की तरह लगता है। मुझे ऑपरेटर के नए और "नए ऑपरेटर" के आंतरिक कामकाज के बारे में कई (कई) साल पहले का एक लेख याद आता है। ऑपरेटर नया () स्थान आवंटित करता है। नया ऑपरेटर कंस्ट्रक्टर को उस आवंटित स्थान के साथ कॉल करता है। एक कंस्ट्रक्टर का पता लेना "विशेष" है क्योंकि कंस्ट्रक्टर को कॉल करने के लिए जगह की आवश्यकता होती है। इस तरह के एक निर्माता को कॉल करने की पहुंच प्लेसमेंट नई के साथ है।
बिल डोर

1
"अस्तित्व" शब्द उस विस्तार को अस्पष्ट करता है कि किसी वस्तु का पता हो सकता है और स्मृति आवंटित की गई है लेकिन आरंभिक नहीं है। सदस्य फ़ंक्शन पर या नहीं, मुझे लगता है कि यह पॉइंटर प्राप्त करना फ़ंक्शन को एक सदस्य फ़ंक्शन बनाता है क्योंकि यह स्पष्ट रूप से ऑब्जेक्ट इंस्टेंस (भले ही अनइंस्टाल्यूटेड) के साथ जुड़ा हुआ है। उस ने कहा, उत्तर एक अच्छा बिंदु उठाता है: निर्माणकर्ता एकमात्र सदस्य कार्य है जिसे एक असंगठित वस्तु पर बुलाया जा सकता है।
प्रिक्सोलिटिक

कोई बात नहीं, जाहिरा तौर पर उनके पास "विशेष सदस्य कार्यों" का पदनाम है। C ++ 11 मानक के खंड 12: "डिफ़ॉल्ट कंस्ट्रक्टर (12.1), कॉपी कंस्ट्रक्टर और कॉपी असाइनमेंट ऑपरेटर (12.8), मूव कंस्ट्रक्टर और मूव असाइनमेंट ऑपरेटर (12.8), और डिस्ट्रक्टर (12.4) विशेष विशेष कार्य हैं ।"
22

और 12.1: "एक निर्माता आभासी नहीं होगा (10.3) या स्थिर (9.4)।" (मेरा जोर)
प्रिक्सॉलिटिक

1
तथ्य यह है कि यदि आप डिबग प्रतीकों के साथ संकलन करते हैं और स्टैक ट्रेस की तलाश करते हैं, तो वास्तव में निर्माणकर्ता के लिए एक संकेतक है। मैं इस पॉइंटर को पाने के लिए सिंटैक्स को खोजने में सक्षम नहीं था ( &A::Aमेरे द्वारा दिए गए किसी भी कंपाइलर में काम नहीं करता है।)
alfC

-3

इसका कारण यह है कि उनके पास कोई वापसी प्रकार का कंस्ट्रक्टर नहीं है और आप मेमोरी में कंस्ट्रक्टर के लिए कोई स्थान नहीं बचा रहे हैं। जैसे डिक्लेरेशन के दौरान वेरिएबल के मामले में यू करते हैं। उदाहरण के लिए: यदि u सरल चर X लिखता है तो संकलक त्रुटि उत्पन्न करेगा क्योंकि संकलक इसका अर्थ नहीं समझेगा। लेकिन जब आप इंट x लिखते हैं; तब संकलक को पता चलता है कि यह डेटा चर टाइप करता है, इसलिए यह चर के लिए कुछ स्थान आरक्षित करेगा।

निष्कर्ष: - इसलिए निष्कर्ष यह है कि रिटर्न प्रकार के बहिष्करण के कारण इसे स्मृति में पता नहीं मिलेगा।


1
कंस्ट्रक्टर में कोड को मेमोरी में एक पता होना चाहिए क्योंकि यह कहीं न कहीं होना है। स्टैक पर इसके लिए स्थान आरक्षित करने की आवश्यकता नहीं है, लेकिन यह स्मृति में कहीं होना चाहिए। आप मानों को वापस नहीं करने वाले कार्यों का पता ले सकते हैं। (void)(*fptr)()बिना रिटर्न वैल्यू वाले फ़ंक्शन को पॉइंटर घोषित करता है।
प्रिक्सोलिटिक

2
आप प्रश्न के बिंदु से चूक गए - मूल पोस्ट ने कंस्ट्रक्टर के लिए कोड का पता लेने के बारे में पूछा, न कि वह परिणाम जो कि कंस्ट्रक्टर ने प्रदान किया था। इसके अलावा, इस बोर्ड पर, कृपया पूर्ण शब्दों का उपयोग करें: "यू" "आप" के लिए स्वीकार्य प्रतिस्थापन नहीं है।
BobDalgleish

श्री praxeolitic, मुझे लगता है कि अगर हम किसी वापसी प्रकार का उल्लेख नहीं करते हैं तो संकलक ctor के लिए एक विशेष मेमोरी लोकेशन सेट नहीं करेगा और यह स्थान आंतरिक रूप से सेट किया गया है .... क्या हम किसी भी चीज का पता c ++ में ला सकते हैं जो कि इसके द्वारा नहीं दिया गया है संकलक? अगर गलत है तो कृपया मुझे सही उत्तर के साथ सही करें
लवलीश गोयल

और मुझे संदर्भ चर के बारे में भी बताएं। क्या हम संदर्भ चर का पता प्राप्त कर सकते हैं? यदि नहीं, तो क्या पता प्रिंटफ ("% u", & (((j))); मुद्रण है अगर & j = x जहां x = 10 है? क्योंकि
प्रिंटफ

-4

मैं एक जंगली अनुमान लगाऊंगा:

सी ++ कंस्ट्रक्टर और डिस्ट्रॉक्टर बिल्कुल भी कार्य नहीं करते हैं: वे मैक्रोज़ हैं। वे उस दायरे में अन्तर्निहित हो जाते हैं जहाँ वस्तु का निर्माण होता है, और वह क्षेत्र जहाँ वस्तु नष्ट होती है। बदले में, कोई भी निर्माता या विध्वंसक नहीं है, वस्तु सिर्फ आईएस है।

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

C ++ "ऑब्जेक्ट" की वर्चुअल टेबल एक जावास्क्रिप्ट ऑब्जेक्ट की तरह नहीं है, जहां आप इसके 'कंस्ट्रक्टर को प्राप्त कर सकते हैं और रनटाइम के दौरान इसमें से ऑब्जेक्ट्स बना सकते हैं new XMLHttpRequest.constructor, बल्कि पॉइंटर्स का एक संग्रह जो गुमनाम फ़ंक्शंस में काम करता है, जो इस ऑब्जेक्ट के साथ इंटरफेस के रूप में कार्य करता है। , वस्तु बनाने की क्षमता को छोड़कर। और इससे ऑब्जेक्ट को "हटाने" का भी कोई मतलब नहीं है, क्योंकि यह एक संरचना को हटाने की कोशिश कर रहा है, आप नहीं कर सकते: यह सिर्फ एक स्टैक लेबल है, बस इसे किसी अन्य लेबल के तहत कृपया लिखें: आप इसके लिए स्वतंत्र हैं 4 पूर्णांक के रूप में एक वर्ग का उपयोग करें:

/* i imagine this string gets compiled into a struct, one of which's members happens to be a const char * which is initialized to exactly your string: no function calls are made during construction. */
std::string a = "hello, world";
int *myInt = (int *)(*((void **)&a));
myInt[0] = 3;
myInt[1] = 9;
myInt[2] = 20;
myInt[3] = 300;

कोई स्मृति रिसाव नहीं है, कोई समस्या नहीं है, सिवाय इसके कि आप प्रभावी रूप से स्टैक स्पेस का एक गुच्छा बर्बाद करते हैं जो ऑब्जेक्ट इंटरफेसिंग और स्ट्रिंग के लिए आरक्षित है, लेकिन यह आपके प्रोग्राम को नष्ट करने वाला नहीं है (जब तक आप इसका उपयोग करने की कोशिश नहीं करते हैं। एक तार के रूप में फिर से)।

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

सारांश: सी ++ वस्तुओं का कोई पता नहीं है कि वे क्या हैं; उनके साथ हस्तक्षेप करने के लिए सभी उपकरण सांख्यिकीय रूप से झुके हुए हैं, और रनटाइम में खो गए हैं। यह कक्षाओं को डेटा के साथ भरने के रूप में कुशल बनाता है, और किसी भी फ़ंक्शन को कॉल किए बिना सीधे उस डेटा के साथ काम करना (ये फ़ंक्शन इनबिल्ड हैं)।

यह COM / ObjectiveC के दृष्टिकोणों के साथ-साथ जावास्क्रिप्ट से पूरी तरह से अलग है, जो रनटाइम ओवरहेड, मेमोरी मैनेजमेंट, कंस्ट्रक्शन के कॉल की कीमत पर टाइप जानकारी को गतिशील रूप से बनाए रखता है, क्योंकि कंपाइलर इस जानकारी को फेंक नहीं सकते: गतिशील प्रेषण के लिए। यह बदले में हमें रनटाइम में हमारे प्रोग्राम के लिए "टॉक" करने की क्षमता देता है, और इसे प्रतिबिंबित करने योग्य घटकों के होने के दौरान इसे विकसित करता है।


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

उत्तर भोली है, मैं सिर्फ अपना अनुमान व्यक्त करना चाहता था कि क्यों निर्माता / विध्वंसक को संदर्भित नहीं किया जा सकता है। मैं मानता हूं कि आभासी कक्षाओं के मामले में, व्यवहार्य बने रहना चाहिए, और पता योग्य कोड स्मृति में होना चाहिए, ताकि व्यवहार्य इसे संदर्भित कर सकें। हालाँकि, वे वर्ग जो वर्चुअल क्लास को लागू नहीं करते हैं, वे इनलाइन प्रतीत होते हैं, जैसा कि std :: string के मामले में है। सब कुछ इन-बिल्ट नहीं होता है, लेकिन ऐसी चीजें जो स्मृति में कहीं "न्यूनतम" कोड ब्लॉक में न्यूनतम रूप से नहीं लगती हैं। इसके अलावा, कोड ढेर को कैसे भ्रष्ट करता है? यकीन है कि हम स्ट्रिंग खो दिया है, लेकिन अन्यथा हम सब किया था पुनर्व्याख्या।
दिमित्री

स्मृति भ्रष्टाचार कंप्यूटर प्रोग्राम में तब होता है जब स्मृति स्थान की सामग्री को अनजाने में संशोधित किया जाता है। यह कार्यक्रम इसे जानबूझकर करता है और उस स्ट्रिंग का उपयोग करने की कोशिश नहीं करता है, इसलिए कोई भ्रष्टाचार नहीं है, बस स्टैक स्पेस को बर्बाद कर दिया है। लेकिन हाँ, स्ट्रिंग के अपरिवर्तनीय को बनाए नहीं रखा जाता है, यह गुंजाइश को अव्यवस्थित करता है (जिसके अंत में, स्टैक बरामद होता है)।
दिमित्री

स्ट्रिंग कार्यान्वयन के आधार पर आप बाइट्स पर लिख सकते हैं जो आप नहीं करना चाहते हैं। यदि स्ट्रिंग कुछ इस तरह है struct { int size; const char * data; };(जैसे आप मान लेते हैं) आप एक स्मृति पते पर 4 * 4 बाइट्स = 16 बाइट्स लिखते हैं, जहाँ आप केवल एक x86 मशीन पर 8 बाइट्स सुरक्षित रखते हैं, इसलिए अन्य डेटा पर 8 बाइट्स लिखे जाते हैं (जो आपके स्टैक को दूषित कर सकते हैं) )। सौभाग्य से, std::stringआमतौर पर शॉर्ट स्ट्रिंग्स के लिए कुछ इन-प्लेस ऑप्टिमाइज़ेशन होते हैं, इसलिए कुछ प्रमुख एसटीडी कार्यान्वयन का उपयोग करते समय यह आपके उदाहरण के लिए पर्याप्त होना चाहिए।
हॉफमैले

@ हॉफमैले आप बिल्कुल सही हैं, यह 4 बाइट्स हो सकता है यह 8, या 1 बाइट भी हो सकता है। हालाँकि एक बार जब आप स्ट्रिंग के आकार को जान लेते हैं, तो आप यह भी जान लेते हैं कि वह मेमोरी वर्तमान दायरे में स्टैक पर है, और आप इसे कृपया उपयोग कर सकते हैं। मेरी बात यह थी कि यदि आप संरचना को जानते हैं, तो यह COM ऑब्जेक्ट्स के विपरीत वर्ग के बारे में किसी भी जानकारी के स्वतंत्र तरीके से पैक किया जाता है, जिसमें यूनुड के व्यवहार्य के हिस्से के रूप में अपनी कक्षा की पहचान करने वाला एक यूआईडी है। बदले में, कंपाइलर इस डेटा को सीधे इनलाइनिंग के माध्यम से एक्सेस करता है, या स्टैक्ड फ़ंक्शंस को मंगवाता है।
दिमित्री
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.