2012-03-15 9 views
22

मैं पिछले कुछ दिनों से सी ++ 11 के साथ खेल रहा हूं, और मैं कुछ अजीब के साथ आया था।क्यों 'std :: vector <int> b {2};' एक 1-तत्व वेक्टर बनाएं, न कि 2-तत्व वाला एक?

अगर मैं समान रूप से एक पूर्णांक को प्रारंभ करना चाहते हैं:

int a{5}; 

लेकिन अगर मैं :: वेक्टर एक एसटीडी करने के लिए एक ही बात करते हैं:

std::vector<int> b{2}; 

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

std::vector<int> c{{2}}; 
std::vector<int> d = {2}; 

लेकिन ख की घोषणा की तरह नहीं है - यह असंगत लगता है। मैंने कुछ अन्य सामानों को एक ही प्रभाव में देखा है। मैं क्या पूछ रहा हूं - क्या यह व्यवहार अंतिम सी ++ 11 मानक में है, या यह सिर्फ एक मसौदे में है जिसे जल्दी लागू किया गया था? यदि हां, मानकों की समिति ने इस व्यवहार को क्यों शामिल किया? ऐसा लगता है कि यह वर्दी प्रारंभिकरण के पूरे उद्देश्य को हरा देता है, क्योंकि किसी को याद रखना होगा कि कौन से वर्गों में प्रारंभकर्ता सूची निर्माता हैं, और उन वर्गों के साथ {} के बजाय पुराने() वाक्यविन्यास का उपयोग करना है। या एक वर्दी प्रारंभिक रूप से पूरी तरह से गुजरता है।

यह एक बड़ा "गोचा" जैसा लगता है। लेकिन इसके लिए फायदे हो सकते हैं जिनके बारे में मुझे जानकारी नहीं है।

संपादित करें: इस कोड:

#include <iostream> 
#include <vector> 

int main() { 
    std::vector<int> a{2}; 
    for (auto x: a) { 
     std::cout << x << std::endl; 
    } 
    return 0; 
} 

आउटपुट "2" जीसीसी 4.6.2

+1

@ildjarn: मैं इसे जीसीसी पर पुष्टि कर सकता हूं, और चूंकि इसकी प्रारंभिक सूची सीटीओआर है, ऐसा लगता है कि यह सही काम है। – PlasmaHH

+0

ध्यान दें कि वर्दी प्रारंभिक (झूठा) वादा का मतलब यह नहीं है कि आप हर जगह {} द्वारा प्रतिस्थापित कर सकते हैं, बस, कि अब आप बहुत अधिक स्थानों पर {} का उपयोग कर सकते हैं। – PlasmaHH

+1

मैं सी ++ 11 विशेषज्ञ नहीं हूं, लेकिन मैंने बस एक प्रशिक्षण कक्षा ली है, और यह मेरे लिए सही लग रहा है। – Almo

उत्तर

21

हाँ, इस व्यवहार करना है, सूची-प्रारंभ

गैर कुल वर्ग प्रकार टी की वस्तुओं सूची-प्रारंभ (8.5.4) कर रहे हैं, अधिभार संकल्प द्वारा §13.3.1.7 प्रारंभ के अनुसार दो चरणों में निर्माता का चयन करता है:

- शुरू में, उम्मीदवार कार्यों प्रारंभकर्ता-सूची वर्ग T के निर्माताओं (8.5.4) कर रहे हैं और तर्क सूची की एक एकल तर्क के रूप में प्रारंभकर्ता सूची होते हैं।

- यदि कोई व्यवहार्य प्रारंभकर्ता-सूची निर्माता पाया जाता है, अधिभार संकल्प फिर से प्रदर्शन किया, जहां उम्मीदवार कार्यों सब वर्ग T के निर्माता ये हैं और तर्क सूची प्रारंभकर्ता सूची के तत्वों से युक्त है।

"वर्दी intialization के पूरे उद्देश्य" के रूप में ... "समान प्रारंभिक" एक विपणन शब्द है, और बहुत अच्छा वर्णन नहीं है। मानक में शुरुआती प्लस सूची-प्रारंभिकरण के सभी सामान्य रूप हैं, लेकिन कोई "वर्दी प्रारंभिक" नहीं है। सूची प्रारंभिकरण प्रारंभिकरण का अंतिम रूप नहीं है, यह उपयोगिता बेल्ट में बस एक और उपकरण है।

+1

ठीक है। स्पष्टीकरण के लिए धन्यवाद। मानक समिति को सिर्फ इतना क्यों नहीं चाहिए कि लोग std :: vector a ({2}) लिखें ;? इस तरह कंपाइलर को एक नया नया प्रारंभिक वाक्यविन्यास लागू करने की आवश्यकता नहीं है और इसे प्राइमेटिव्स पर लागू करें। यदि उद्देश्य लोगों को अधिक स्थानों पर {} का उपयोग करने की अनुमति देना है, तो यह एक एंटीफेचर की तरह लगता है। पहले() और {} प्रत्येक के पास अपनी जगह थी। लेकिन अब, {} हमेशा उपयोग किया जा सकता है, सिवाय इसके कि जब यह नहीं हो सकता है। तो मेरी आंत प्रतिक्रिया पूरी तरह से नई सुविधा से बचने के लिए है और कष्टप्रद गठिया से बचने के लिए पुराने वाक्यविन्यास का उपयोग करना है। –

+0

ठीक है। बस अपना संपादन देखा। यह सिर्फ दुर्भाग्यपूर्ण है कि हर कोई सूची प्रारंभिकरण को सभी के रूप में बेच रहा है और सी ++ के लिए सभी प्रारंभिकरण समाप्त कर रहा है और फिर इसे एक बड़ी सुविधा के रूप में बता रहा है। मुझे जरूरी नहीं लगता कि यह सबसे सहज या लगातार व्यवहार है, लेकिन एक कारण है कि मुझे मानक लिखना नहीं है: पी –

+0

@ रॉबर्ट मेसन: यह एक बड़ी सुविधा है, लेकिन किसी भी माध्यम से नहीं "सभी और सब खत्म "। मैं नाखुश हूं कि लोग यही सोचते हैं, क्योंकि यह सच नहीं है। –

2

मानक कहा गया है कि प्रारंभकर्ता सूची निर्माता दूसरों पर पूर्वता लेता है पर। यह केवल एक मामला है जहां यह संभव नहीं है () को {} के साथ प्रतिस्थापित करें। अन्य हैं, उदाहरण के लिए {} प्रारंभिक रूपांतरण को संकुचित करने की अनुमति नहीं देता है।

+0

हां, यह सी ++ 11 §13.3.1.7/1 द्वारा समर्थित है। – ildjarn

+1

हां, लेकिन मेरे लिए यह std :: vector a (2) लेने के बराबर है और फिर यह कह रहा है कि std :: vector a2 वही काम करता है। यह मेरे लिए बहुत संगत प्रतीत नहीं होता है। और वर्दी प्रारंभिकता का पूरा बिंदु AFAIK को अधिक स्थिरता की अनुमति देना है। तो यह क्यों जोड़ें? –

+1

@ रॉबर्ट मेसन, मुझे लगता है कि कोई यहां "वर्दी" पढ़ सकता है जिसका अर्थ है कि आप एक std :: vector, std :: array, c-style array, std :: set, std :: list और उपयोगकर्ता परिभाषित संग्रह प्रकारों को प्रारंभ कर सकते हैं उसी तरह। मैं यह नहीं कह रहा कि यह बहुत अच्छा है, मुझे इसके चारों ओर अपना सिर लेने में थोड़ी देर लग गई। – juanchopanza

5

समान प्रारंभिक अर्थ यह नहीं है कि आप क्या सोचते हैं। यह सी ++ में प्रकारों के बीच प्रारंभिकता को और अधिक समान बनाने के लिए जोड़ा गया था।

typedef struct dog_ { 
    float height; 
    int weight; 
} dog; 
int main() { 
    dog Spot = { 25.6, 45}; 
    dog Data[3] = { Spot, {6.5, 7} }; 
    std::array<dog, 2> data = { { Spot, {6.5, 7} } }; //only in C++ obviously 
    return 0; 
} 

यह valid C and C++ code है, और कई कई वर्षों के लिए कर दिया गया है: तर्क यह है। यह वास्तव में सुविधाजनक था, लेकिन आपको याद रखना था कि यह केवल पीओडी प्रकारों के साथ काम करता था। लोगों ने लंबे समय से शिकायत की है कि std::vector<int> data = { 3, 7, 4, 1, 8}; करने का कोई तरीका नहीं है, लेकिन कुछ वर्ग (std::array) प्रारंभिक सूची कन्स्ट्रक्टरों को अनुमति देने के अजीब तरीकों से लिखे गए थे।

तो सी ++ 11 के लिए, समिति ने इसे बनाया ताकि हम वेक्टर और अन्य शांत कक्षाएं भी ऐसा कर सकें। इसने सभी प्रकार के वर्दी का निर्माण किया, ताकि हम रचनाकारों के माध्यम से प्रारंभ करने के लिए {} और मूल्य सूचियों से भी उपयोग कर सकें। जिस समस्या में आप चल रहे हैं, वह यह है कि std::initializer_list<int> के साथ कन्स्ट्रक्टर अधिभार सबसे अच्छा मिलान है, और पहले चुना जाएगा। इस प्रकार, std::vector<int> b{2}; का मतलब उस निर्माता को कॉल नहीं करता है जो int लेता है, इसके बजाय इसका अर्थ int मानों की सूची से vector बनाएं। उस प्रकाश में, यह सही समझ में आता है कि यह vector बनाएगा जिसमें 2 का एक मान होगा। एक अलग कन्स्ट्रक्टर को कॉल करने के लिए, आपको () सिंटैक्स का उपयोग करना होगा ताकि सी ++ जानता है कि आप किसी सूची से प्रारंभ नहीं करना चाहते हैं।

+3

"* रचनाकारों के लिए' (} 'के बजाय' {} 'का उपयोग करने का मतलब नहीं है, यह मूर्खतापूर्ण होगा। *" असल में, इसका मतलब यह है कि अगर कोई कन्स्ट्रक्टर ओवरलोड नहीं है जो केवल 'std: : प्रारंभकर्ता_सूची <> 'उदाहरण। – ildjarn

+2

स्ट्रॉस्ट्रप उनके एफएक्यू में उल्लेख करता है http://www2.research.att.com/~bs/C++0xFAQ.html#uniform-init कि समान प्रारंभिक _ _ प्रारंभिककरण_ के लिए है। लेकिन अपवाद हैं (जैसे 'std :: startizer_list's) जहां आपको "पुरानी शैली" का उपयोग करना होगा। – evnu

+0

@ildjarn: आईएमओ यह नहीं होना चाहिए। अगर कोई मुझे औचित्य दे सकता है कि यह _should_ अन्य रचनाकारों को क्यों कॉल करता है, [मैं सुनना चाहता हूं] (http://chat.stackoverflow.com/rooms/10/loungec)। इस बीच, मैंने उस वाक्य को कुछ कम विवादास्पद में बदल दिया। –

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