क्या ऑटो सी ++ कोड को समझने में कठिन बनाता है?


122

मैंने हर्ब सटर द्वारा एक सम्मेलन देखा जहां वह हर C ++ प्रोग्रामर को उपयोग करने के लिए प्रोत्साहित करता है auto

मुझे कुछ समय पहले C # कोड पढ़ना था जहां varबड़े पैमाने पर इस्तेमाल किया गया था और कोड को समझना बहुत कठिन था - हर बार varइस्तेमाल होने पर मुझे राइट साइड के रिटर्न प्रकार की जांच करनी थी। कभी-कभी एक से अधिक बार, क्योंकि मैं थोड़ी देर बाद चर का प्रकार भूल गया!

मुझे पता है कि संकलक को प्रकार पता है और मुझे इसे लिखना नहीं है, लेकिन यह व्यापक रूप से स्वीकार किया जाता है कि हमें प्रोग्रामर के लिए कोड लिखना चाहिए, न कि संकलक के लिए।

मुझे यह भी पता है कि लिखना अधिक आसान है:

auto x = GetX();

से:

someWeirdTemplate<someOtherVeryLongNameType, ...>::someOtherLongType x = GetX();

लेकिन यह केवल एक बार लिखा जाता है और यह GetX()समझने के लिए कि किस प्रकार xका रिटर्न रिटर्न कई बार चेक किया जाता है।

इससे मुझे आश्चर्य हुआ- क्या autoC ++ कोड को समझना कठिन है?


29
क्या आपको हर बार रिटर्न प्रकार की जांच करने की आवश्यकता है ? कोड से प्रकार स्पष्ट क्यों नहीं है? autoअक्सर चीजों को पढ़ना मुश्किल हो जाता है जब वे पहले से ही पढ़ने में कठिन होते हैं, यानी, बहुत लंबे समय तक कार्य करना, चरों का नाम खराब होना आदि। शालीनता से नामांकित चर के साथ छोटे कार्यों पर, प्रकारों को जानना # 1 आसान या # 2 अप्रासंगिक में से एक होना चाहिए।
आर। मार्टिनो फर्नांडिस 14

25
उपयोग करने की "कला" का उपयोग autoकरने के लिए निर्धारित करने जैसा बहुत कुछ है typedef। यह निर्धारित करना आपके लिए है कि यह कब बाधा डालता है और कब मदद करता है।
१०:१२ बजे १०:१२

18
मुझे लगा कि मुझे भी यही समस्या है, लेकिन तब मुझे महसूस हुआ कि मैं बिना किसी प्रकार के कोड को समझे ही समझ सकता हूं। उदाहरण: "ऑटो idx = get_index ();" इसलिए idx एक इंडेक्स को पकड़े हुए है। सटीक प्रकार क्या है, ज्यादातर मामलों के लिए काफी अप्रासंगिक है।
प्लाज़्मा एचएच

31
इसलिए न लिखें auto x = GetX();, इससे बेहतर नाम चुनें xजो वास्तव में आपको बताता है कि यह उस विशिष्ट संदर्भ में क्या करता है ... वैसे भी यह अपने प्रकार से अधिक उपयोगी है।
योनातान वैकली

11
यदि अधिक प्रकार के इंजेक्शन का उपयोग करने से प्रोग्रामर के लिए कोड को पढ़ना मुश्किल हो जाता है, तो कोड या प्रोग्रामर को गंभीर सुधार की आवश्यकता होती है।
सीए मैककैन

जवाबों:


99

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

लंबा उत्तर और तर्क:

एक स्पष्ट प्रकार लिखें (बजाय auto) केवल जब आप वास्तव में स्पष्ट रूप से एक प्रकार के लिए प्रतिबद्ध करना चाहते हैं, जिसका अर्थ है कि आप हमेशा स्पष्ट रूप से उस प्रकार के लिए रूपांतरण प्राप्त करना चाहते हैं। मेरे सिर के ऊपर से, मुझे दो मुख्य मामले याद हैं:

  • (सामान्य) initializer_listआश्चर्य जो auto x = { 1 };घटाता है initializer_list। यदि आप नहीं चाहते हैं initializer_list, तो टाइप करें - यानी, स्पष्ट रूप से रूपांतरण के लिए पूछें।
  • (दुर्लभ) अभिव्यक्ति टेम्पलेट्स का मामला, जैसे कि auto x = matrix1 * matrix 2 + matrix3;एक सहायक या प्रॉक्सी प्रकार को पकड़ता है जो प्रोग्रामर को दिखाई देने के लिए नहीं है। कई मामलों में, यह उस प्रकार को पकड़ने के लिए ठीक और सौम्य है, लेकिन कभी-कभी यदि आप वास्तव में चाहते हैं कि यह ढह जाए और गणना करे, तब टाइप करें - अर्थात, फिर से स्पष्ट रूप से रूपांतरण के लिए कहें।

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

  • सुधार:auto गारंटी का उपयोग करके आपको सही प्रकार मिलेगा। जैसा कि कहा जाता है, यदि आप खुद को दोहराते हैं (प्रकार को अतिरेक से कहें), तो आप झूठ बोल सकते हैं और इसे गलत कर सकते हैं। यहाँ एक सामान्य उदाहरण है: void f( const vector<int>& v ) { for( /*…*- इस बिंदु पर, यदि आप इट्रेटर के प्रकार को स्पष्ट रूप से लिखते हैं, तो आप लिखना याद रखना चाहते हैं const_iterator(क्या आपने?), जबकि autoयह सही है।
  • स्थिरता और मजबूती: उपयोग करना autoआपके कोड को परिवर्तन के चेहरे पर और अधिक मजबूत बनाता है, क्योंकि जब अभिव्यक्ति का प्रकार बदलता है, autoतो सही प्रकार का समाधान जारी रहेगा। यदि आप इसके बजाय एक स्पष्ट प्रकार के लिए प्रतिबद्ध हैं, तो अभिव्यक्ति के प्रकार को बदलने से मौन रूपांतरणों को इंजेक्ट किया जाएगा जब नया प्रकार पुराने प्रकार में परिवर्तित हो जाता है, या अनावश्यक प्रकार का विराम तब होता है जब नया प्रकार अभी भी पुराने प्रकार की तरह कार्य करता है लेकिन पुराने में परिवर्तित नहीं होता है टाइप करें (उदाहरण के लिए, जब आप ए mapको बदलते हैं unordered_map, जो हमेशा ठीक होता है यदि आप ऑर्डर पर निर्भर नहीं होते हैं, तो autoअपने पुनरावृत्तियों के लिए उपयोग करके आप मूल रूप से स्विच map<>::iteratorकर सकते हैं unordered_map<>::iterator, लेकिन उपयोग करकेmap<>::iterator हर जगह स्पष्ट रूप से इसका मतलब है कि आप एक यांत्रिक कोड फिक्स रिपल पर अपना बहुमूल्य समय बर्बाद कर रहे हैं, जब तक कि कोई इंटर्न नहीं चल रहा है और आप उन पर उबाऊ काम बंद कर सकते हैं)।
  • प्रदर्शन: क्योंकि autoकोई अंतर्निहित रूपांतरण की गारंटी नहीं होगी, यह डिफ़ॉल्ट रूप से बेहतर प्रदर्शन की गारंटी देता है। यदि इसके बजाय आप टाइप करते हैं, और इसके लिए रूपांतरण की आवश्यकता है, तो आप अक्सर चुपचाप एक रूपांतरण प्राप्त करेंगे कि क्या आपने इसकी उम्मीद की थी या नहीं।
  • प्रयोज्य: का उपयोग करते हुए autoइस तरह के lambdas और टेम्पलेट सहायकों के रूप में मुश्किल से जादू और अनिर्वचनीय प्रकार, दोहराए का सहारा की कमी, के लिए अपने ही अच्छा विकल्प है decltypeभाव या की तरह कम कुशल indirections std::function
  • सुविधा: और, हाँ, autoकम टाइपिंग है। मैं उल्लेख करता हूं कि पूर्णता के लिए अंतिम है क्योंकि यह इसे पसंद करने का एक सामान्य कारण है, लेकिन इसका उपयोग करने का सबसे बड़ा कारण नहीं है।

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

हाँ, वहाँ (अब) इस बारे में एक गोटव है।


14
जब मुझे रूपांतरण चाहिए तब भी मुझे ऑटो उपयोगी लगता है। यह मुझे टाइप को दोहराए बिना रूपांतरण के लिए स्पष्ट रूप से पूछने की अनुमति देता है auto x = static_cast<X>(y):। static_castयह स्पष्ट है कि रूपांतरण उद्देश्य पर है और यह परिवर्तन के बारे में संकलक चेतावनी से बचा जाता है बनाता है। आम तौर पर कंपाइलर चेतावनियों से बचना इतना अच्छा नहीं है, लेकिन जब मैंने लिखा है तो रूपांतरण के बारे में चेतावनी नहीं मिलने के साथ मैं ठीक हूं static_cast। हालाँकि, अगर कोई चेतावनी नहीं है, तो मैं ऐसा नहीं करूँगा, लेकिन अगर भविष्य में संभावित खतरनाक तरीके से बदलाव होते हैं तो मैं भविष्य में चेतावनी प्राप्त करना चाहता हूँ।
बजरके हम्मरशोल रून 18

6
मेरे साथ एक बात यह autoहै कि हमें इंटरफेस के खिलाफ (ओओपी अर्थ में नहीं) कार्यक्रम के लिए प्रयास करना चाहिए , न कि विशिष्ट कार्यान्वयन के खिलाफ। यह टेम्प्लेट के साथ समान है, वास्तव में। क्या आप "कोड पढ़ने में कठिन" के बारे में शिकायत करते हैं क्योंकि आपके पास एक टेम्पलेट प्रकार पैरामीटर है Tजो हर जगह उपयोग किया जाता है? नहीं, मुझे ऐसा नहीं लगता। टेम्पलेट्स में भी हम एक इंटरफेस के खिलाफ कोड करते हैं, संकलन-समय बतख-टाइपिंग है जिसे कई लोग इसे कहते हैं।
Xeo

6
"ऑटो गारंटी का उपयोग करने से आपको सही प्रकार मिलेगा।" सच नहीं है। यह केवल गारंटी देता है कि आपको अपने कोड के किसी अन्य भाग द्वारा निर्धारित प्रकार मिलेगा। यह सही है या नहीं यह पूरी तरह से स्पष्ट नहीं है जब आप इसे पीछे छिपाते हैं auto
ऑर्बिट

मैं वास्तव में आश्चर्यचकित हूं कि कोई भी आईडीई के बारे में परवाह नहीं करता है ... यहां तक ​​कि आधुनिक आईडीई भी autoचर के मामले में कक्षा / संरचना की परिभाषा पर कूदने का सही समर्थन नहीं करते हैं , लेकिन लगभग सभी स्पष्ट प्रकार के विनिर्देश के साथ इसे सही ढंग से करते हैं। कोई भी आईडीई का उपयोग नहीं करता है? हर कोई केवल int / float / bool चर का उपयोग करता है? हर कोई स्व-प्रलेखित हेडर के बजाय पुस्तकालयों के लिए बाहरी प्रलेखन पसंद करता है?
एव्टोमेटन

उस GotW: जड़ी बूटीश्रृंखला.com/ 2013 / 08/ 12 / मैं यह नहीं देखता कि कैसे "initializer_list आश्चर्य" एक आश्चर्य है; =RHS के आसपास के ब्रेसिज़ किसी भी अन्य व्याख्या (बार लट init- सूची द्वारा बहुत मतलब नहीं है, लेकिन आप को पता है कि आप क्या शुरू कर रहे हैं, जो एक ऑक्सीमोरन है auto) के साथ की जरूरत है । एक है कि है आश्चर्य की बात है auto i{1}भी बात का अनुमान लगाना initializer_list, नहीं जिसका अर्थ है के बावजूद इस braced init-सूची ले बल्कि इस अभिव्यक्ति लेने के लिए और अपने प्रकार का उपयोग करें ... लेकिन हम पाते हैं initializer_listवहां भी। शुक्र है, C ++ 17 यह सब ठीक करता है।
अंडरस्कोर_ड

112

यह मामला दर मामला है।

यह कभी-कभी समझने के लिए कोड को कठिन बनाता है, कभी-कभी नहीं। उदाहरण के लिए, लें:

void foo(const std::map<int, std::string>& x)
{
   for ( auto it = x.begin() ; it != x.end() ; it++ )
   { 
       //....
   }
}

निश्चित रूप से समझने में आसान है और वास्तविक पुनरावृत्ति घोषणा की तुलना में लिखना आसान है।

मैं थोड़ी देर के लिए C ++ का उपयोग कर रहा हूं, लेकिन मैं गारंटी दे सकता हूं कि मुझे अपने पहले शॉट में एक कंपाइलर त्रुटि मिलेगी क्योंकि मैं इसके बारे में const_iteratorभूलूंगा और शुरू में इसके लिए जाऊंगा iterator... :)

मैं इसे इस तरह के मामलों के लिए उपयोग करूंगा, लेकिन ऐसा नहीं है जहां यह वास्तव में प्रकार (आपकी स्थिति की तरह) को बाधित करता है, लेकिन यह शुद्ध रूप से व्यक्तिपरक है।


45
ठीक ठीक। कौन बिल्ली किस प्रकार की परवाह करता है। यह एक पुनरावृति है। मुझे इस प्रकार की परवाह नहीं है, मुझे केवल यह जानना चाहिए कि मैं इसे पुनरावृति के लिए उपयोग कर सकता हूं।
आर। मार्टिनो फर्नांडिस

5
+1। यहां तक ​​कि अगर आपने इस प्रकार का नाम दिया है std::map<int, std::string>::const_iterator, तो आप इसे नाम देंगे , इसलिए ऐसा नहीं है जैसे कि नाम आपको वैसे भी टाइप के बारे में बताता है।
स्टीव जेसोप

4
@SteveJessop: यह मुझे कम से कम दो बातें बताता है: कुंजी है int, और मूल्य है std::string। :)
नवाज

16
@ नवाज़: और क्योंकि आप इसे कांस्टीट्यूशन का काम नहीं दे सकते it->second। सभी जानकारी जो पिछली पंक्ति में क्या है, का दोहराव है const std::map<int, std::string>& x। कई बार बातें कहना कभी-कभार बेहतर सूचित करता है, लेकिन किसी भी तरह से यह सामान्य नियम नहीं है :-)
स्टीव जेसप

11
टीबीएच मैं for (anX : x)इसे और भी स्पष्ट करना पसंद करूंगा x। सामान्य मामला जहां आपको एक xconst&
इटिलेटर की

94

इसे दूसरे तरीके से देखें। क्या आप लिखते हो:

std::cout << (foo() + bar()) << "\n";

या:

// it is important to know the types of these values
int f = foo();
size_t b = bar();
size_t total = f + b;

std::cout << total << "\n";

कभी-कभी यह स्पष्ट रूप से टाइप करने में मदद नहीं करता है।

यह निर्णय कि आपको जिस प्रकार का उल्लेख करने की आवश्यकता है, वह निर्णय के समान नहीं है, चाहे आप मध्यवर्ती कथनों को परिभाषित करके कई कथनों में कोड को विभाजित करना चाहते हैं। C ++ 03 में दोनों को जोड़ा गया था, आप autoउन्हें अलग करने के तरीके के रूप में सोच सकते हैं।

कभी-कभी प्रकार स्पष्ट करना उपयोगी हो सकता है:

// seems legit    
if (foo() < bar()) { ... }

बनाम

// ah, there's something tricky going on here, a mixed comparison
if ((unsigned int)foo() < bar()) { ... }

ऐसे मामलों में जहां आप एक चर घोषित करते हैं, इसका उपयोग autoकरने से टाइप ठीक हो जाता है जैसे कि यह कई अभिव्यक्तियों में है। आपको शायद अपने लिए तय करने का प्रयास करना चाहिए कि कब पठनीयता में मदद मिलती है और कब बाधा आती है।

आप यह तर्क दे सकते हैं कि हस्ताक्षरित और अहस्ताक्षरित प्रकारों को मिलाना एक गलती है। (वास्तव में, कुछ लोगों का तर्क है कि किसी को अहस्ताक्षरित प्रकारों का उपयोग नहीं करना चाहिए)। कारण यह बेशक एक गलती है कि यह अलग व्यवहार के कारण ऑपरेंड के प्रकार के जैविक रूप से महत्वपूर्ण बना देता है। यदि आपके मूल्यों के प्रकारों को जानना एक बुरी बात है, तो शायद यह भी कोई बुरी बात नहीं है कि उन्हें जानने की आवश्यकता नहीं है। इसलिए बशर्ते कोड पहले से ही अन्य कारणों से भ्रमित न हो, जो autoठीक बनाता है ? ;-)

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


21
+1 autoआपको नामांकित या अप्रमाणित प्रकारों के साथ नामित चर बनाने की अनुमति देता है। सार्थक नाम उपयोगी हो सकते हैं।
मन्कारसे

यदि आप उचित उपयोग के लिए अहस्ताक्षरित का उपयोग करते हैं, तो हस्ताक्षरित और अहस्ताक्षरित मिश्रण: मॉड्यूलर अंकगणित। यह नहीं है यदि आप सकारात्मक पूर्णांक के लिए अहस्ताक्षरित दुरुपयोग करते हैं। लगभग किसी भी कार्यक्रम में अहस्ताक्षरित के लिए उपयोग नहीं किया जाता है, लेकिन मूल भाषा आपके असंबद्ध परिभाषा sizeofको आप पर अहस्ताक्षरित करने के लिए मजबूर करती है ।
जिज्ञासु

27

IMO, आप इसे बहुत उल्टा देख रहे हैं।

यह autoकोड के लिए अग्रणी की बात नहीं है जो अपठनीय या कम पठनीय है। यह (उम्मीद है कि) वापसी मूल्य के लिए एक स्पष्ट प्रकार होने की बात है, इस तथ्य के लिए बना देगा कि यह (स्पष्ट रूप से) स्पष्ट नहीं है कि किसी विशेष फ़ंक्शन द्वारा किस प्रकार लौटाया जाएगा।

कम से कम मेरी राय में, यदि आपके पास एक फ़ंक्शन है जिसका वापसी प्रकार तुरंत स्पष्ट नहीं है, तो यह आपकी समस्या है। फ़ंक्शन क्या करता है यह उसके नाम से स्पष्ट होना चाहिए, और वापसी मूल्य का प्रकार स्पष्ट होना चाहिए कि यह क्या करता है। यदि नहीं, तो समस्या का वास्तविक स्रोत यही है।

अगर यहां कोई समस्या है, तो यह नहीं है auto। यह कोड के बाकी हिस्सों के साथ है, और संभावनाएं बहुत अच्छी हैं कि स्पष्ट प्रकार आपको बस देखने और / या मूल समस्या को ठीक करने के लिए एक बैंड-सहायता के लिए पर्याप्त है। एक बार जब आप उस वास्तविक समस्या को ठीक कर लेते हैं, तो कोड का उपयोग करने की पठनीयता autoआम तौर पर ठीक हो जाएगी।

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

ऐसे मामले में भी, आप कुछ चीजों को स्पष्ट करने में मदद कर सकते हैं। उस स्थिति में, वैश्विक नाम स्थान में सभी कोड शुरू हो गए। बस कुछ नामस्थानों में एक उचित राशि ले जाने से नाम की गड़बड़ी समाप्त हो गई और टाइप-ट्रैकिंग में भी थोड़ी आसानी हुई।


17

सामान्य उपयोग के लिए ऑटो को नापसंद करने के कई कारण हैं:

  1. आप इसे संशोधित किए बिना कोड को रीफ़्रैक्टर कर सकते हैं। हां, यह उन चीजों में से एक है जिन्हें अक्सर ऑटो का उपयोग करने के लाभ के रूप में सूचीबद्ध किया जाता है। बस एक फ़ंक्शन के रिटर्न प्रकार को बदलें, और अगर कोड के सभी जो इसे ऑटो का उपयोग करता है, कोई अतिरिक्त प्रयास की आवश्यकता नहीं है! आप संकलित करते हैं, यह बनाता है - 0 चेतावनियाँ, 0 त्रुटियां - और आप आगे बढ़ते हैं और अपने कोड की जांच करते हैं बिना देखने की गड़बड़ी से निपटने के लिए और संभवतः 80 स्थानों को संशोधित करने के लिए फ़ंक्शन का उपयोग किया जाता है।

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

1 क। मैं "स्व-दस्तावेज कोड" की अवधारणा में विश्वास करता हूं। सेल्फ-डॉक्यूमेंटिंग कोड के पीछे तर्क यह है कि टिप्पणियां आउट-ऑफ-डेट हो जाती हैं, अब यह नहीं दर्शाता है कि कोड क्या कर रहा है, जबकि कोड स्वयं - यदि स्पष्ट तरीके से लिखा गया है - स्व-व्याख्यात्मक है, तो हमेशा अद्यतित रहता है अपने इरादे पर, और आपको बासी टिप्पणियों से भ्रमित नहीं करेगा। यदि कोड को संशोधित करने की आवश्यकता के बिना प्रकार बदले जा सकते हैं, तो कोड / चर स्वयं बासी हो सकते हैं। उदाहरण के लिए:

ऑटो bThreadOK = CheckThreadHealth ();

समस्या को छोड़कर यह है कि CheckThreadHealth () कुछ बिंदु पर एक ब्यूम के बजाय त्रुटि स्थिति, यदि कोई हो, का संकेत करने वाले एक एनुम मान को वापस करने के लिए वापस ले लिया गया था। लेकिन उस बदलाव को करने वाले व्यक्ति कोड की इस विशेष रेखा का निरीक्षण करने से चूक गए, और संकलक को कोई मदद नहीं मिली क्योंकि यह चेतावनी या त्रुटियों के बिना संकलित था।

  1. आप कभी नहीं जान सकते कि वास्तविक प्रकार क्या हैं। यह अक्सर ऑटो के प्राथमिक "लाभ" के रूप में भी सूचीबद्ध होता है। क्यों जानें कि एक फ़ंक्शन आपको क्या दे रहा है, जब आप बस कह सकते हैं, "कौन परवाह करता है? यह संकलन करता है!"

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

यह भी बदतर बनाया जा सकता है यदि आप नहीं जानते कि प्रकार क्या है, लेकिन आप एक चर नाम चुनते हैं जो गलत धारणा बनाता है कि यह क्या है, वास्तव में 1 ए के रूप में एक ही परिणाम प्राप्त करना, लेकिन इसके बजाय बहुत शुरुआत से बाद refactor।

  1. कोड लिखना जब शुरू में लिखते हैं तो यह प्रोग्रामिंग का सबसे अधिक समय लेने वाला हिस्सा नहीं होता है। हां, ऑटो शुरू में कुछ कोड तेजी से लिखता है। डिस्क्लेमर के रूप में, मैं टाइप करता हूं> 100 WPM, इसलिए शायद यह मुझे उतना परेशान न करे जितना दूसरों को। लेकिन अगर मुझे पूरा दिन नया कोड लिखना होता तो मैं एक खुश रहने वाला टूरिस्ट होता। प्रोग्रामिंग का सबसे अधिक समय लेने वाला हिस्सा कोड में हार्ड-टू-प्रजनन, एज-केस बग्स का निदान कर रहा है, जो अक्सर सूक्ष्म गैर-स्पष्ट समस्याओं से उत्पन्न होता है - जैसे कि ऑटो का अत्यधिक उपयोग शुरू होने की संभावना है (संदर्भ बनाम कॉपी,) हस्ताक्षर किए बनाम अहस्ताक्षरित, फ्लोट बनाम इंट, बूल बनाम पॉइंटर, आदि)।

यह मुझे स्पष्ट लगता है कि ऑटो को मुख्य रूप से मानक पुस्तकालय टेम्पलेट प्रकारों के साथ भयानक सिंटैक्स के लिए एक समाधान के रूप में पेश किया गया था। टेम्पलेट सिंटैक्स को ठीक करने की कोशिश करने के बजाय, जो लोग पहले से ही परिचित हैं - जो मौजूदा कोड के सभी होने के कारण लगभग असंभव भी हो सकता है - मूल रूप से समस्या को छिपाने वाले कीवर्ड में जोड़ें। अनिवार्य रूप से जिसे आप "हैक" कह सकते हैं।

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

ऑटो का एक और उपयोगी अनुप्रयोग जो भाषा की क्षमता को बढ़ाता है, जो टाइप-अज्ञेय मैक्रोज़ में अस्थायीता पैदा कर रहा है। यह कुछ ऐसा है जो आप वास्तव में पहले नहीं कर सकते थे, लेकिन अब आप कर सकते हैं।


4
आप इसे किसी न किसी। काश मैं इसे +2 दे पाता।
सेमीस्टर

एक अच्छा "शापित सतर्क" -ए.आर. @ सेमीस्टर: वहाँ यह है।
Deduplicator

मुझे एक और उपयोगी मामला मिला है auto something = std::make_shared<TypeWithLongName<SomeParam>>(a,b,c);:। :-)
14

14

हां, यदि आप इसका उपयोग नहीं करते हैं तो यह आपके चर के प्रकार को जानना आसान बनाता है auto। सवाल यह है: क्या आपको कोड पढ़ने के लिए अपने चर के प्रकार को जानने की आवश्यकता है? कभी-कभी जवाब हां होगा, कभी-कभी नहीं। उदाहरण के लिए, जब एक से एक पुनरावृत्ति हो रही है std::vector<int>, क्या आपको पता है कि यह एक std::vector<int>::iteratorया auto iterator = ...;पर्याप्त होगा? सब कुछ है कि कोई भी एक पुनरावृत्त के साथ क्या करना चाहता है, इस तथ्य से दिया जाता है कि यह एक पुनरावृत्ति है - यह सिर्फ इस बात से कोई फर्क नहीं पड़ता कि विशेष रूप से क्या है।

autoउन परिस्थितियों में उपयोग करें जब यह आपके कोड को पढ़ने के लिए कठिन नहीं बनाता है।


12

व्यक्तिगत रूप से मैं autoकेवल तभी उपयोग करता हूं जब यह प्रोग्रामर के लिए बिल्कुल स्पष्ट हो कि वह क्या है।

उदाहरण 1

std::map <KeyClass, ValueClass> m;
// ...
auto I = m.find (something); // OK, find returns an iterator, everyone knows that

उदाहरण 2

MyClass myObj;
auto ret = myObj.FindRecord (something)// NOT OK, everyone needs to go and check what FindRecord returns

5
यह खराब नामकरण की स्पष्ट पठनीयता का एक स्पष्ट उदाहरण है, वास्तव में ऑटो नहीं। किसी को भी बेहूदा अंदाजा नहीं है कि "DoSomethingWeird" क्या करता है, इसलिए ऑटो का उपयोग करना या इसे और अधिक पठनीय नहीं बनाया जाएगा। आपको डॉक्स की जांच करनी होगी।
आर। मार्टिनो फर्नांडीस

4
ठीक है, यह अब कुछ बेहतर है। मुझे अभी भी लगता है कि चर का नाम खराब है, हालांकि, जो अभी भी दर्द होता है। क्या आप लिखना auto record = myObj.FindRecord(something)चाहते हैं यह स्पष्ट होगा कि चर प्रकार रिकॉर्ड किया गया था। या इसका नामकरण itया इसके समान यह स्पष्ट करता है कि यह एक पुनरावृत्ति देता है। ध्यान दें कि, भले ही आपने उपयोग नहीं किया हो auto, चर का ठीक से नामकरण करने का मतलब होगा कि आपको फ़ंक्शन में कहीं से भी टाइप देखने के लिए घोषणा में वापस जाने की आवश्यकता नहीं है । मैंने अपना डाउनवोट हटा दिया क्योंकि उदाहरण अब एक पूर्ण स्ट्रोमैन नहीं है, लेकिन मैं अभी भी यहां तर्क नहीं खरीदता हूं।
आर। मार्टिनो फर्नांडीस

2
@ R.MartinhoFernandes में जोड़ने के लिए: सवाल यह है कि क्या वास्तव में यह महत्वपूर्ण है कि वास्तव में "रिकॉर्ड" क्या है? मुझे लगता है कि यह अधिक महत्वपूर्ण है कि यह एक रिकॉर्ड है, वास्तविक अंतर्निहित आदिम प्रकार एक और अमूर्त परत है .. तो एक ऑटो के बिना शायद होगा:MyClass::RecordTy record = myObj.FindRecord (something)
paul23

2
@ paul23: ऑटो बनाम प्रकार का उपयोग करने से आपको क्या फायदा होता है, अगर आपकी एकमात्र आपत्ति है "मुझे नहीं पता कि यह कैसे उपयोग करना है"। या तो आप इसे वैसे भी देखते हैं।
GMANNICKG

3
@GManNickG यह मुझे महत्वहीनता का सटीक प्रकार बताता है।
पौल

10

यह प्रश्न राय को हल करता है, जो प्रोग्रामर से प्रोग्रामर तक अलग-अलग होगा, लेकिन मैं कहूंगा कि नहीं। वास्तव में कई मामलों में इसके ठीक विपरीत, autoप्रोग्रामर को माइनूटी के बजाय तर्क पर ध्यान केंद्रित करने की अनुमति देकर कोड को समझने में आसान बनाने में मदद कर सकता है ।

यह विशेष रूप से जटिल टेम्पलेट प्रकारों के चेहरे में सच है। यहाँ एक सरलीकृत और वंचित उदाहरण है। जिसे समझना आसान है?

for( std::map<std::pair<Foo,Bar>, std::pair<Baz, Bot>, std::less<BazBot>>::const_iterator it = things_.begin(); it != things_.end(); ++it )

.. या ...

for( auto it = things_.begin(); it != things_.end(); ++it )

कुछ कहेंगे कि दूसरा समझना आसान है, दूसरे लोग पहले कह सकते हैं। फिर भी अन्य लोग यह कह सकते हैं कि autoप्रोग्राम का उपयोग करने वाले लोगों की ड्यूटि-डाउन में योगदान करने का एक गंभीर उपयोग हो सकता है, लेकिन यह एक और कहानी है।


4
+1 हाहा, हर कोई std::mapउदाहरण प्रस्तुत कर रहा है , इसके अतिरिक्त जटिल टेम्पलेट तर्कों के साथ।
नवाज

1
@ नवाज़: एस का उपयोग करते हुए पागल-लंबे टेम्पलेट नामों के साथ आना आसान है map। :)
जॉन डिब्लिंग

@ नवाज़: लेकिन मुझे आश्चर्य है कि तब कोई भी बेहतर और अधिक पठनीय विकल्प के रूप में छोरों पर आधारित रेंज के साथ क्यों नहीं आ रहा है ...
प्लाज्मा 12

1
@PlasmaHH, पुनरावृत्तियों के साथ सभी छोरों को श्रेणी-आधारित के साथ प्रतिस्थापित नहीं किया जा सकता है forजैसे कि यदि पुनरावृत्तियों को लूप बॉडी में अमान्य कर दिया जाता है और इसलिए पूर्व-वृद्ध होने की आवश्यकता होती है या सभी में वृद्धि नहीं की जाती है।
योनातन वैखली

@PlasmaHH: मेरे मामले में, MSVC10 लूप्स के लिए रेंज-आधारित नहीं है। चूंकि MSVC10 मेरा गो-टू सी ++ 11 टेस्टेड है, इसलिए मुझे वास्तव में उनके साथ ज्यादा अनुभव नहीं है।
जॉन डिब्लिंग

8

अब तक कई अच्छे जवाब, लेकिन मूल प्रश्न पर ध्यान केंद्रित करने के लिए, मुझे लगता है कि हर्ब autoउदारतापूर्वक उपयोग करने की सलाह में बहुत दूर चला जाता है । आपका उदाहरण एक मामला है जहां autoस्पष्ट रूप से उपयोग करने से पठनीयता को नुकसान पहुंचता है। कुछ लोग इस पर जोर देते हैं कि यह आधुनिक आईडीई के साथ एक गैर-मुद्दा है जहां आप एक चर पर मंडरा सकते हैं और प्रकार देख सकते हैं, लेकिन मैं असहमत हूं: यहां तक ​​कि ऐसे लोग जो हमेशा आईडीई का उपयोग करते हैं, उन्हें कभी-कभी कोड के स्निपेट को अलगाव में देखने की जरूरत होती है (कोड समीक्षाओं के बारे में सोचें) उदाहरण के लिए) और एक आईडीई मदद नहीं करेगा।

निचला रेखा: autoजब यह मदद करता है तो उपयोग करें : छोरों के लिए पुनरावृत्तियों। इसका उपयोग तब न करें जब यह पाठक को टाइप का पता लगाने के लिए संघर्ष करता है।


6

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

मान लीजिए कि आपको एक फ़ंक्शन मिला है, जो प्लेटफ़ॉर्म-विशिष्ट प्रकार के साथ कुछ देता है:

#ifdef PLATFROM1
__int256 getStuff();
#else //PLATFORM2
__int128 getStuff();
#endif

चुड़ैल का उपयोग आप पसंद करेंगे?

#ifdef PLATFORM1
__int256 stuff = getStuff();
#else
__int128 stuff = getStuff();
#endif

या बस

auto stuff = getStuff();

ज़रूर लिख सकते हैं

#define StuffType (...)

के रूप में अच्छी तरह से कहीं, लेकिन करता है

StuffType stuff = getStuff();

वास्तव में एक्स के प्रकार के बारे में कुछ और बताओ? यह बताता है कि वहां से क्या लौटा है, लेकिन यह वही है जो ऑटो है। यह केवल निरर्थक है - 'सामान' यहां 3 बार लिखा गया है - मेरी राय में यह 'ऑटो' संस्करण की तुलना में कम पठनीय है।


5
प्लेटफ़ॉर्म विशिष्ट प्रकारों को संभालने का सही तरीका typedefउनके लिए है।
सेमीस्टर

3

पठनीयता व्यक्तिपरक है; आपको स्थिति को देखने और यह तय करने की आवश्यकता होगी कि सबसे अच्छा क्या है।

जैसा कि आपने बताया, ऑटो के बिना, लंबी घोषणाएं बहुत अव्यवस्था पैदा कर सकती हैं। लेकिन जैसा कि आपने बताया, लघु घोषणाएँ प्रकार की जानकारी को हटा सकती हैं जो मूल्यवान हो सकती हैं।

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

फिर संगति है; यह आपके लिए कितना महत्वपूर्ण है? क्या आप कुछ हिस्सों में ऑटो चाहते हैं और अन्य में स्पष्ट घोषणाएं, या एक सुसंगत विधि भर में?


2

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


2
सबसे अच्छे रूप में, आपको ऐसे लोगों के नाम लिखने होंगे myComplexDerivedType, जो लापता प्रकार के लिए मेकअप करना पसंद करते हैं, जो कोड को टाइप रिपीटीशन (हर जगह चर का उपयोग किया जाता है) से अलग कर देता है, और जो लोगों को इसके नाम में चर के उद्देश्य को छोड़ने के लिए लुभाता है । मेरा अनुभव यह है कि कोड में बाधाओं को सक्रिय रूप से डालने के लिए अनुत्पादक के रूप में कुछ भी नहीं है।
सेमीस्टर

2

मेरे पास दो दिशानिर्देश हैं:

  • यदि चर का प्रकार स्पष्ट है, तो ऑटो का उपयोग करने के लिए लिखना कठिन है।

    auto range = 10.0f; // Obvious
    
    for (auto i = collection.cbegin(); i != cbegin(); ++i) // Tedious if collection type
    // is really long
    
    template <typename T> ... T t; auto result = t.get(); // Hard to determine as get()
    // might return various stuff
    
  • यदि आपको विशिष्ट रूपांतरण की आवश्यकता है या परिणाम प्रकार स्पष्ट नहीं है और भ्रम पैदा कर सकता है।

    class B : A {}; A* foo = new B(); // 'Convert'
    
    class Factory { public: int foo(); float bar(); }; int f = foo(); // Not obvious
    

0

हाँ। यह वर्बोसिटी कम कर देता है लेकिन आम गलतफहमी यह है कि वर्बोसिटी पठनीयता कम हो जाती है। यह केवल तभी सच है जब आप कोड को आत्मसात करने की अपनी वास्तविक क्षमता के बजाय सौन्दर्यशास्त्रीय होने पर विचार करते हैं - जो कि ऑटो का उपयोग करके नहीं बढ़ाया जाता है। सबसे आम तौर पर उद्धृत उदाहरण में, वेक्टर पुनरावृत्तियों, यह सतह पर दिखाई दे सकता है कि ऑटो का उपयोग करने से आपके कोड की पठनीयता बढ़ जाती है। दूसरी ओर, आप हमेशा यह नहीं जानते कि ऑटो कीवर्ड आपको क्या देगा। आपको उसी तार्किक पथ का अनुसरण करना होगा जैसा कि संकलक उस आंतरिक पुनर्निर्माण को बनाने के लिए करता है, और बहुत समय, विशेष रूप से पुनरावृत्तियों के साथ, आप गलत धारणा बनाने जा रहे हैं।

दिन के अंत में 'ऑटो' कोड और स्पष्टता की पठनीयता, वाक्यात्मक और सौंदर्यवादी 'स्वच्छता' के लिए बलिदान करता है (जो कि केवल आवश्यक है क्योंकि पुनरावृत्तियों में अनावश्यक रूप से वाक्यविन्यास होता है) और किसी भी पंक्ति में शायद 10 कम वर्ण टाइप करने की क्षमता है। यह जोखिम के लायक नहीं है, या प्रयास में दीर्घकालिक शामिल है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.