2010-03-04 5 views
24

और के तत्वों के लिए डिफ़ॉल्ट कन्स्ट्रक्टर की आवश्यकता के लिए मैं अपनी खुद की सरणी कक्षा कैसे लिख सकता हूं? अभी, जब मैं अंतरिक्ष आवंटित करने के लिए नया [] करता हूं, तो मुझे एक डिफ़ॉल्ट कन्स्ट्रक्टर की आवश्यकता होती है।std :: vector के तत्वों को डिफ़ॉल्ट कन्स्ट्रक्टर की आवश्यकता क्यों नहीं है?

std :: वेक्टर नहीं है।

वे यह जादू कैसे करते हैं?

उत्तर

7

आप बाइट्स के एक ब्लॉक का आवंटन सकता है, तो placement new का उपयोग नई प्रतिलिपि निर्माता के माध्यम से T के इंस्टेंस (अपने पैरामीट्रिक प्रकार) बनाने के लिए (बेशक निर्माता डिफ़ॉल्ट नहीं) जब नए आइटम वेक्टर की पीठ को धक्का दे रहे हैं। यह "एन डिफ़ॉल्ट-प्रारंभिक टीएस का वेक्टर" बनाने की अनुमति नहीं देगा (जो std :: वेक्टर बना सकता है - यही कारण है कि को इस उद्देश्य के लिए डिफ़ॉल्ट कन्स्ट्रक्टर रखने की आवश्यकता है), लेकिन आप वैक्टर बना सकते हैं जो खाली शुरू होता है और टीएस उन्हें धक्का दे सकता है।

+0

मैं पहली जगह में स्थान कैसे आवंटित करूं? malloc? – anon

+2

@anon: इस पर एक नज़र डालें कि 'वेक्टर' कैसे करता है ... यह एक आवंटक का उपयोग करता है, उदाहरण के लिए 'new_allocator'। मेरे (पुराने) सिगविन इंस्टॉलेशन में यह इस प्रकार काम करता है: '{return static_cast <_Tp*> (:: ऑपरेटर नया (__ n * sizeof (_Tp))); } 'या' malloc_allocator' इस तरह से करता है: 'सूचक __ret = static_cast <_Tp*> (malloc (__ n * sizeof (_Tp))); – Dan

26

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

आप इस तरह की कक्षा को उसी तरह लिख सकते हैं: हर बार जब आपको अपनी सरणी में एक नया तत्व बनाने की आवश्यकता होती है, तो उपयोगकर्ता को प्रतिलिपि बनाने के लिए तत्व की आवश्यकता होती है। इस मामले में उस मूल तत्व का निर्माण उपयोगकर्ता की ज़िम्मेदारी बन जाता है।

हर बार ऐसा लगता है मानो std::vector आप से एक डिफ़ॉल्ट निर्माता "की आवश्यकता है", यह बस का अर्थ है कि कहीं न कहीं आप vector रों तरीकों में से कुछ की एक डिफ़ॉल्ट तर्क पर भरोसा किया, यानी यह था तुम कौन default- करने की कोशिश की वेक्टर नहीं, एक तत्व का निर्माण। वेक्टर स्वयं, फिर से, डिफ़ॉल्ट-निर्माण तत्वों को कभी भी कोशिश नहीं करेगा।

आदेश स्मृति आवंटन के दौरान डिफ़ॉल्ट निर्माता आवश्यकता से बचने के लिए, मानक पुस्तकालय कच्चे अप्रारंभीकृत स्मृति ब्लॉक आवंटित करता है और फिर तुरंत कि कच्चे स्मृति ब्लॉक (जो कुछ new[] ऐसा नहीं कर सकते है) में नए तत्व कॉपी-निर्माण करती है। यह कार्यक्षमता std::allocator कक्षा में incapsulated है। आप अपने कोड में std::allocator का भी उपयोग कर सकते हैं, जिसका अर्थ है कि "जादू" तुरंत आपके लिए भी उपलब्ध है।

नोट: उपरोक्त सी ++ भाषा विनिर्देश के पूर्व-सी ++ 11 संस्करण पर लागू होता है। सी ++ 11 ने कई चीजें बदल दीं। और ये परिवर्तन ऐसी स्थितियां बनाते हैं जिनमें std::vector आंतरिक रूप से डिफ़ॉल्ट कन्स्ट्रक्टर का उपयोग कर सकते हैं।

यह भी ध्यान देने योग्य बात है कि यहां तक ​​कि मूल सी ++ 98 विनिर्देश अनुमति कार्यान्वयन आदेश मानक पुस्तकालय इंटरफ़ेस को लागू करने मेंके बजाय डिफ़ॉल्ट तर्क अधिक भार समारोह का उपयोग करने के लायक हो सकता है। इसका मतलब है कि औपचारिक रूप से std::vector का वैध सी ++ 98 कार्यान्वयन संभव है जो डिफ़ॉल्ट कन्स्ट्रक्टर आंतरिक रूप से का उपयोग करता है।

+3

दूसरी तरफ, वे कुछ जादू का उपयोग करते हैं जो बहुत संबंधित हैं: std :: आवंटक वस्तु। –

+1

'std :: vector :: emplace_back()' डिफ़ॉल्ट कन्स्ट्रक्टर को कॉल करता है। आम तौर पर 'emplace_back (Args ...)' कन्स्ट्रक्टर को तर्क के साथ कहते हैं 'Args ... ' –

+2

@Angelorf यह उत्तर सी ++ 11 जारी होने से पहले लिखा गया था :) असल में सी ++ 11 ने वेक्टर के व्यवहार को बदल दिया x (5) '- अब इसे डिफ़ॉल्ट कन्स्ट्रक्टर को 5 बार कॉल करने के रूप में निर्दिष्ट किया गया है, जबकि सी ++ 03 में इसका मतलब है कि आप एक 'एक्स' को डिफॉल्ट-निर्माण करते हैं और फिर वेक्टर प्रति-निर्माण 5 बार उपयोग करता है, और आपका डिफ़ॉल्ट बाद में नष्ट हो गया है। –

11

std::vector केवल तत्व को डिफ़ॉल्ट कन्स्ट्रक्टर रखने की आवश्यकता है यदि आप इसे इस तरह से उपयोग करते हैं जिसके लिए डिफ़ॉल्ट कन्स्ट्रक्टर की आवश्यकता होती है।इसलिए इस कोड (किसी हटाए गए जवाब से चोरी) संकलन नहीं होगा, क्योंकि X एक डिफ़ॉल्ट ctor नहीं है:

#include <vector> 

struct X 
{ 
    X(int) {} 
}; 

int main(void) 
{ 
    std::vector<X> x(1); // vector of length 1, second argument defaults to X() !! 
    return 0; 
} 

लेकिन अगर आप इस तरह के बजाय main लिखें:

int main(void) 
{ 
    std::vector<X> x; // make empty vector 
    x.push_back(X(1)); 
    return 0; 
} 

तो यह काम करता है ठीक।

+10

पहला संस्करण संकलित नहीं होगा, क्योंकि 'std :: vector x (1) '' std :: वेक्टर x (1, X()) 'के लिए एक लघुरूप है। यह वास्तव में * आप * है जो डिफ़ॉल्ट रूप से डिफ़ॉल्ट कन्स्ट्रक्टर का उपयोग कर रहा है, न कि 'वेक्टर'। डिफ़ॉल्ट तर्क का मूल्यांकन "आपकी तरफ" किया जाता है। – AnT

+0

@AndreyT: महान बिंदु। – Dan