[] का उपयोग करते समय C ++ मानचित्र प्रकार के तर्क के लिए खाली कंस्ट्रक्टर की आवश्यकता क्यों होती है?


99

C ++ मानक सूची और डिफ़ॉल्ट-निर्माण योग्य प्रकार भी देखें

एक बड़ा मुद्दा नहीं है, सिर्फ इसलिए कि मैं नहीं चाहता कि मेरी कक्षा विशेष तर्कों के बिना कभी भी त्वरित हो।

#include <map>

struct MyClass
{
    MyClass(int t);
};

int main() {
    std::map<int, MyClass> myMap;
    myMap[14] = MyClass(42);
}

यह मुझे निम्न g ++ त्रुटि देता है:

/us/

यदि मैं एक डिफ़ॉल्ट रचनाकार जोड़ता हूं तो यह ठीक संकलित करता है; मुझे लगता है कि यह गलत वाक्य रचना के कारण नहीं है।


ऊपर दिए गए कोड MinGW (g ++ 3.4.5) और MSVC ++ 2008 पर ठीक संकलित करते हैं, बशर्ते कि MyType के लिए एक टाइफेड दिया जाए और एक अर्धविराम वर्ग के अंत में संलग्न हो। आप कुछ और कर रहे होंगे (जैसे कि कॉलिंग ऑपरेटर [] जैसा कि बी बी द्वारा बताया गया है) - कृपया पूरा कोड पोस्ट करें ।
j_random_hacker 5

आह, हाँ, तुम सही हो। करूँगा।
निक बोल्टन

हाँ, myMap के उपयोग के बिना आप नहीं जानते कि मानचित्र वर्ग के लिए क्या संकलित किया जाना चाहिए। लाइब्रेरी प्रदाता और संस्करण भी मदद कर सकते हैं।
ग्रेग डोमजान

जवाबों:


165

यह समस्या ऑपरेटर [] के साथ आती है। SGI प्रलेखन से उद्धरण:

data_type& operator[](const key_type& k)- उस वस्तु का संदर्भ देता है जो किसी विशेष कुंजी से जुड़ी होती है। यदि मानचित्र में पहले से ही ऐसा ऑब्जेक्ट नहीं है, operator[] तो डिफ़ॉल्ट ऑब्जेक्ट को सम्मिलित करता है data_type()

यदि आपके पास डिफ़ॉल्ट कंस्ट्रक्टर नहीं है, तो आप इन्सर्ट / फ़ंक्शंस का उपयोग कर सकते हैं। निम्नलिखित उदाहरण ठीक काम करता है:

myMap.insert( std::map< int, MyClass >::value_type ( 1, MyClass(1) ) );
myMap.find( 1 )->second;

11
उत्कृष्ट उत्तर - emplaceC ++ 11 में एक विकल्प के रूप में भी ध्यान दें insert
गौरव

3
कॉल std::<map>::value_typeमें ऐसा क्यों है insert?
थोमथोम

1
डिफ़ॉल्ट कंस्ट्रक्टर को उपयोगकर्ता परिभाषित करने की आवश्यकता क्यों है?
schuess

@ मुझे लगता है कि ऐसा नहीं होने का कोई कारण नहीं है: = defaultबस ठीक काम करना चाहिए।
अंडरस्कोर_ड

स्थिति 'मानचित्र में पहले से ही ऐसी वस्तु नहीं है' का मूल्यांकन रनटाइम पर किया जाएगा। एक संकलन समय त्रुटि क्यों?
गौरव सिंह

7

हाँ। एसटीएल कंटेनरों में मूल्यों को कॉपी शब्दार्थ बनाए रखने की आवश्यकता है। IOW, उन्हें आदिम प्रकार (जैसे int) का व्यवहार करने की आवश्यकता है, जिसका अर्थ है, अन्य चीजों के बीच, उन्हें डिफ़ॉल्ट-रचनात्मक होना चाहिए।

इसके (और अन्य आवश्यकताओं के बिना) एसटीएल कंटेनरों को लागू करने वाले डेटा संरचनाओं पर विभिन्न आंतरिक कॉपी / चाल / स्वैप / संचालन की तुलना करना मुश्किल होगा।

C ++ मानक के संदर्भ में, मुझे लगता है कि मेरा उत्तर सटीक नहीं था। डिफ़ॉल्ट-निर्माण वास्तव में, आवश्यकता नहीं है :

20.1.4.1 से:

डिफ़ॉल्ट निर्माता की आवश्यकता नहीं है। कुछ कंटेनर क्लास सदस्य फ़ंक्शन हस्ताक्षर डिफ़ॉल्ट तर्क के रूप में डिफ़ॉल्ट निर्माता को निर्दिष्ट करते हैं। टी () एक अच्छी तरह से परिभाषित अभिव्यक्ति होनी चाहिए ...

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

वास्तविक आवश्यकताएं (23.1.3) एसटीएल कंटेनरों में संग्रहीत सभी मूल्यों से हैं CopyConstructibleऔर Assignable

विशेष रूप से कंटेनरों के लिए अन्य विशिष्ट आवश्यकताएं भी हैं, जैसे कि होना Comparable(उदाहरण के लिए मानचित्र में कुंजियाँ)।


संयोग से, निम्न कोमो पर कोई त्रुटि नहीं है :

#include <map>

class MyClass
{
public:
    MyClass(int t);
};

int main()
{
    std::map<int, MyClass> myMap;
}

तो यह एक जी ++ समस्या हो सकती है।


2
क्या आपको लगता है कि बी बी [] ऑपरेटर के संबंध में कुछ हो सकता है?
निक बोल्टन

13
यह कोड शायद इसलिए संकलित करता है क्योंकि आप myMap []
jfritz42

3

संग्रहीत प्रकार की stl :: मानचित्र की आवश्यकताओं की जाँच करें। कई stl संग्रह की आवश्यकता है कि संग्रहीत प्रकार में कुछ विशिष्ट गुण (डिफ़ॉल्ट निर्माता, प्रतिलिपि निर्माता, आदि) हैं।

तर्क के बिना कंस्ट्रक्टर को stl :: मैप की आवश्यकता होती है, क्योंकि इसका उपयोग तब किया जाता है, जब ऑपरेटर [] कुंजी के साथ लगाया जाता है, जो पहले से ही मैप द्वारा नहीं रखा गया है। इस मामले में ऑपरेटर [] नई प्रविष्टि को सम्मिलित करता है जिसमें पैरामीटर रहित निर्माणकर्ता का उपयोग करके निर्मित नई कुंजी और मूल्य शामिल होता है। और फिर यह नया मान लौटाया जाता है।


-2

अगर जांच:

  • आप भूल गए '' कक्षा की घोषणा के बाद।
  • MyType को तदनुसार घोषित किया जाना चाहिए था।
  • कोई डिफ़ॉल्ट कंस्ट्रक्टर नहीं ...

एसटीडी :: नक्शा घोषणा सही लगती है, मुझे लगता है।


यदि मैं एक डिफॉल्ट कंस्ट्रक्टर जोड़ता हूं तो कंपाइल ठीक है।
निक बोल्टन

-2

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

आप एक नक्शा <int, smartptr <MyClass>> का उपयोग करके स्मार्ट पॉइंटर्स के साथ इसे प्राप्त कर सकते हैं, लेकिन यह अशक्त बिंदुओं के लिए जाँच का ओवरहेड जोड़ता है।


2
+0। जोड़ी <T, U> का उपयोग केवल ठीक प्रकार के T और U के साथ डिफ़ॉल्ट निर्माणकर्ताओं में किया जा सकता है - केवल एक चीज जो इस मामले में उपयोग नहीं की जा सकती है वह है जोड़ी <T, U> का स्वयं का डिफ़ॉल्ट निर्माता। मानचित्र का कोई भी सभ्य गुणवत्ता वाला कार्यान्वयन <K, V> इस डिफ़ॉल्ट निर्माणकर्ता का उपयोग नहीं करेगा क्योंकि यह K और V को सीमित करता है।
j_random_hacker
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.