2012-04-02 14 views
87

सी ++ 11 में, हमारे पास कक्षाओं को शुरू करने के लिए वह नया वाक्यविन्यास है जो हमें चर की शुरुआत करने की संभावनाओं की एक बड़ी संख्या देता है।ब्रेस-संलग्न प्रारंभकर्ता का उपयोग कब करें?

{ // Example 1 
    int b(1); 
    int a{1}; 
    int c = 1; 
    int d = {1}; 
} 
{ // Example 2 
    std::complex<double> b(3,4); 
    std::complex<double> a{3,4}; 
    std::complex<double> c = {3,4}; 
    auto d = std::complex<double>(3,4); 
    auto e = std::complex<double>{3,4}; 
} 
{ // Example 3 
    std::string a(3,'x'); 
    std::string b{3,'x'}; // oops 
} 
{ // Example 4 
    std::function<int(int,int)> a(std::plus<int>()); 
    std::function<int(int,int)> b{std::plus<int>()}; 
} 
{ // Example 5 
    std::unique_ptr<int> a(new int(5)); 
    std::unique_ptr<int> b{new int(5)}; 
} 
{ // Example 6 
    std::locale::global(std::locale("")); // copied from 22.4.8.3 
    std::locale::global(std::locale{""}); 
} 
{ // Example 7 
    std::default_random_engine a {}; // Stroustrup's FAQ 
    std::default_random_engine b; 
} 
{ // Example 8 
    duration<long> a = 5; // Stroustrup's FAQ too 
    duration<long> b(5); 
    duration<long> c {5}; 
} 

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

जब यह टेम्पलेट कोड की बात आती है, तो वाक्यविन्यास बदलने से अलग-अलग अर्थ हो सकते हैं, इसलिए सही तरीके से जाना आवश्यक है।

मुझे आश्चर्य है कि क्या एक सार्वभौमिक दिशानिर्देश है जिसे सिंटैक्स को चुना जाना चाहिए।

+1

से {} initialisation अनायास ही व्यवहार का एक उदाहरण: स्ट्रिंग (50, 'एक्स') बनाम स्ट्रिंग {50, 'एक्स'} [यहां] (http://stackoverflow.com/questions/27063811/c11-string50- एक्स-बनाम-स्ट्रिंग 50-एक्स) –

उत्तर

57

मुझे लगता है कि निम्नलिखित एक अच्छा दिशानिर्देश हो सकता है:

  • (एकल) मूल्य आप का इरादा है के साथ आरंभ कर रहे हैं सही मूल्य वस्तु, उपयोग प्रतिलिपि की होने के लिए अगर (=) प्रारंभिकरण (क्योंकि तब त्रुटि के मामले में, आप कभी भी एक स्पष्ट कन्स्ट्रक्टर का आकलन नहीं करेंगे, जो आमतौर पर प्रदान किए गए मान को अलग-अलग समझता है)। उन जगहों पर जहां प्रतिलिपि प्रारंभिकरण उपलब्ध नहीं है, देखें कि ब्रेस प्रारंभिकरण में सही अर्थशास्त्र है, और यदि ऐसा है, तो इसका उपयोग करें; अन्यथा कंस्ट्रैसिस प्रारंभिकरण का उपयोग करें (यदि वह भी उपलब्ध नहीं है, तो आप वैसे भी भाग्य से बाहर हैं)।

  • तो मानों आप के साथ आरंभ कर रहे हैं मानों की सूची, वस्तु (एक वेक्टर/सरणी, या एक जटिल संख्या के वास्तविक/काल्पनिक भाग के तत्वों की तरह) में संग्रहीत हो घुंघराले ब्रेसिज़ आरंभीकरण उपयोग करने के लिए कर रहे हैं अगर उपलब्ध हो।

  • तो मानों आप के साथ आरंभ कर रहे हैं नहीं मान संग्रहीत करने के लिए है, लेकिन इरादा मूल्य/वस्तु की स्थिति का वर्णन कर रहे हैं, कोष्ठक का उपयोग। उदाहरण vector का आकार तर्क या fstream का फ़ाइल नाम तर्क हैं। सामान्य कोड की

+0

यदि मुझे संदेह है, उदाहरण के लिए 'std :: locale (" ")'? – helami

+4

@ user1304032: एक लोकेल एक स्ट्रिंग नहीं है, इसलिए आप कॉपी प्रारंभिकरण का उपयोग नहीं करेंगे। एक लोकेल में स्ट्रिंग भी नहीं होती है (यह उस स्ट्रिंग को कार्यान्वयन विवरण के रूप में संग्रहीत कर सकती है, लेकिन यह इसका उद्देश्य नहीं है), इसलिए आप ब्रेस प्रारंभिकरण का उपयोग नहीं करेंगे। इसलिए दिशानिर्देश ब्रांडेसिस प्रारंभिकरण का उपयोग करने के लिए कहते हैं। – celtschk

+0

मुझे लगता है कि यह एक अच्छा दिशानिर्देश है क्योंकि यह उस उद्देश्य को व्यक्त करता है जिसे कोड के उद्देश्य को समझने में मदद करनी चाहिए। – Sean

25

मुझे पूरा यकीन है कि कभी भी सार्वभौमिक दिशानिर्देश नहीं होगा। मेरे दृष्टिकोण हमेशा याद है कि

  1. प्रारंभकर्ता सूची कंस्ट्रक्टर्स
  2. सभी मानक पुस्तकालय कंटेनरों अन्य निर्माताओं से प्राथमिकता दी जाती और std :: basic_string प्रारंभकर्ता सूची कंस्ट्रक्टर्स है घुंघराले ब्रेसिज़ उपयोग करने के लिए है।
  3. घुंघराले ब्रेस प्रारंभिक संकुचन रूपांतरणों की अनुमति नहीं देता है।

तो गोल और घुंघराले ब्रेसिज़ अदला-बदले नहीं हैं। लेकिन यह जानकर कि वे कहां भिन्न हैं, मुझे ज्यादातर मामलों में राउंड ब्रैकेट प्रारंभिकरण पर घुंघराले का उपयोग करने की अनुमति मिलती है (कुछ मामलों में जहां मैं वर्तमान में कंपाइलर बग नहीं कर सकता)।

+5

घुंघराले ब्रेसिज़ का नुकसान है कि मैं गलती से सूची निर्माता को कॉल कर सकता हूं। गोल ब्रैकेट नहीं करते हैं। क्या डिफ़ॉल्ट रूप से राउंड ब्रैकेट का उपयोग करने का कोई कारण नहीं है? – helami

+0

साथ ही, क्या मुझे हमेशा 'int i {0}' लिखना चाहिए, 'int i = 0;' की बजाय 'संकुचन के कारण? यहां तक ​​कि स्ट्राउस्ट्रप अब तक नहीं जाता है। – helami

+0

@ user1304032 मान लें कि क्या आपको पता है कि कौन से वर्ग प्रारंभकर्ता सूची निर्माता हैं तो आपको गलती करने की संभावना कम है। लेकिन यह एक व्यापार बंद है, और मेरे लिए व्यक्तिगत रूप से, घुंघराले ब्रेसिज़ अच्छी तरह से काम करता है। – juanchopanza

16

बाहर (अर्थात टेम्पलेट्स), आप (और मैं करता हूँ) कर सकते हैं हर जगह ब्रेसेस का उपयोग करें।

struct foo { 
    // Ok 
    std::string a = { "foo" }; 

    // Also ok 
    std::string b { "bar" }; 

    // Not possible 
    std::string c("qux"); 

    // For completeness this is possible 
    std::string d = "baz"; 
}; 

या के लिए समारोह तर्क:

void foo(std::pair<int, double*>); 
foo({ 42, nullptr }); 
// Not possible with parentheses without spelling out the type: 
foo(std::pair<int, double*>(42, nullptr)); 

चर के लिए मैं T t = { init }; या T t { init }; के बीच ज्यादा ध्यान नहीं देते हैं एक लाभ यह है कि यह हर जगह भी इन-क्लास प्रारंभ के लिए काम करता है, उदाहरण के लिए है शैलियों, मुझे नाबालिग होने का अंतर मिलता है और सबसे खराब स्थिति में केवल explicit कन्स्ट्रक्टर का दुरुपयोग करने के बारे में उपयोगी कंपाइलर संदेश होता है।

प्रकार है कि std::initializer_list स्वीकार हालांकि स्पष्ट रूप से कभी कभी गैर std::initializer_list कंस्ट्रक्टर्स की जरूरत है के लिए (शास्त्रीय उदाहरण है std::vector<int> twenty_answers(20, 42);)। तब ब्रेसिज़ का उपयोग न करना ठीक है।


जब जेनेरिक कोड (यानी टेम्पलेट्स) की बात आती है तो आखिरी पैराग्राफ में कुछ चेतावनियां बढ़नी चाहिए थीं। पर विचार करें निम्नलिखित:

template<typename T, typename... Args> 
std::unique_ptr<T> make_unique(Args&&... args) 
{ return std::unique_ptr<T> { new T { std::forward<Args>(args)... } }; } 

फिर auto p = make_unique<std::vector<T>>(20, T {}); बनाता आकार 2 का एक वेक्टर अगर T उदा है int, या आकार 20 का वेक्टर यदि Tstd::string है। , std::is_constructible डायरेक्ट-आरंभीकरण के संदर्भ में है हम ब्रेस-आरंभीकरण जो defers उपयोग कर रहे हैं, जबकि: एक बहुत भांजीमार संकेत कुछ बहुत गलत यहाँ पर जा रहा है कि वहाँ नहीं है कि कोई विशेषता है कि आप यहां (SFINAE साथ जैसे) को बचा सकता है है प्रत्यक्ष-आरंभिक यदि और केवल पर कोई कन्स्ट्रक्टर std::initializer_list हस्तक्षेप नहीं कर रहा है। इसी तरह std::is_convertible कोई मदद नहीं है।

मैंने जांच की है कि वास्तव में यह एक विशेषता है जो इसे ठीक कर सकती है, लेकिन मैं इसके बारे में अत्यधिक आशावादी नहीं हूं। किसी भी मामले में मुझे नहीं लगता कि हम बहुत गुम हो जाएंगे, मुझे लगता है कि make_unique<T>(foo, bar) का परिणाम T(foo, bar) के बराबर निर्माण में बहुत सहज है; विशेष रूप से दिया गया है कि make_unique<T>({ foo, bar }) काफी भिन्न है और केवल foo और bar के समान होने पर समझ में आता है।

इसलिए सामान्य कोड के लिए मैं केवल मूल्य प्रारंभ (जैसे T t {}; या T t = {};) है, जो बहुत सुविधाजनक है के लिए ब्रेसेस का उपयोग करें और मैं सी ++ 03 रास्ता T t = T(); से बेहतर लगता है। अन्यथा यह या तो प्रत्यक्ष प्रारंभ वाक्य रचना (अर्थात T t(a0, a1, a2);), या कभी कभी डिफ़ॉल्ट निर्माण (T t; stream >> t; केवल मामले मैं कहाँ का उपयोग करें कि मुझे लगता है कि किया जा रहा है) है। भले ही वास्तविक प्रकार टेम्पलेट पैरामीटर पर निर्भर

template<typename T, typename... Args> 
std::unique_ptr<T> make_unique(Args&&... args) 
{ return std::unique_ptr<T> { new T(std::forward<Args>(args)...) }; } 

यह अभी भी std::unique_ptr<T>, के निर्माण के लिए ब्रेसिज़ उपयोग करता है:

मतलब यह नहीं है कि सभी ब्रेसिज़ हालांकि खराब हैं, सुधारों के साथ पिछले उदाहरण पर विचार T

+0

@interjay मेरे कुछ उदाहरणों को वास्तव में इसके बजाय हस्ताक्षरित प्रकारों का उपयोग करने की आवश्यकता हो सकती है, उदा। 'make_unique (20u, T {}) '' '' '' '' 'हस्ताक्षरित' या 'std :: string' होने के लिए। विवरण पर भी निश्चित नहीं है। (ध्यान दें कि मैंने प्रत्यक्ष प्रारंभिक बनाम ब्रेस प्रारंभिकरण के बारे में उम्मीदों पर भी टिप्पणी की है जैसे कि पूर्ण-फ़ॉरवर्डिंग फ़ंक्शंस।) 'Std :: string c ("qux");' इन-क्लास प्रारंभिकरण के रूप में काम करने के लिए निर्दिष्ट नहीं किया गया है व्याकरण में सदस्य समारोह घोषणाओं के साथ अस्पष्टताएं। –

+0

@interjay मैं पहली बार आपसे सहमत नहीं हूं, 8.5.4 सूची प्रारंभ करने के लिए स्वतंत्र महसूस करें और 13.3.1.7 सूची-प्रारंभिकरण द्वारा आरंभ करें। दूसरे के लिए, आपको जो लिखा है (जो ** कक्षा में ** प्रारंभिकरण के बारे में है) और/या सी ++ व्याकरण (उदाहरण के लिए * सदस्य-घोषणाकर्ता *, जो संदर्भ * ब्रेस-या- बराबर-प्रारंभकर्ता *)। –

+0

हम्म, आप सही हैं - मैं पहले जीसीसी 4.5 के साथ परीक्षण कर रहा था जो कि मैं जो कह रहा था उसकी पुष्टि करने लग रहा था, लेकिन जीसीसी 4.6 आपके साथ सहमत है। और मैंने इस तथ्य को याद किया कि आप कक्षा के प्रारंभिकरण के बारे में बात कर रहे थे। मैं क्षमाप्रार्थी हूं। – interjay

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