2010-11-14 8 views
53

एसटीएल सी ++ दुनिया का एक महत्वपूर्ण टुकड़ा है, अधिकांश कार्यान्वयन स्टेपानोव और मुसर द्वारा शुरुआती प्रयासों से प्राप्त होते हैं।अधिकांश एसटीएल कार्यान्वयन में कोड इतनी गड़बड़ क्यों है?

मेरा प्रश्न कोड की आलोचना को दिया गया है, और यह लोगों के लिए भय और सीखने के उद्देश्यों के लिए अच्छी तरह लिखित सी ++ के उदाहरण देखने के लिए प्राथमिक स्रोतों में से एक है: एसटीएल के विभिन्न कार्यान्वयन क्यों देखने के लिए घृणित हैं एक सौंदर्यशास्त्र बिंदु से सी ++ कोड लिखने के तरीके के बारे में ठोस और आम तौर पर अच्छे उदाहरण।

नीचे दिए गए कोड उदाहरण उन स्थानों पर कोड-समीक्षा पास नहीं करेंगे जो मैंने चरम नामकरण, लेआउट, मैक्रोज़ और ऑपरेटरों के उपयोग से भिन्न कारणों के लिए काम किया है जिनके लिए वास्तव में क्या होता है यह जानने के लिए एक साधारण नज़र से अधिक की आवश्यकता होती है ।

template<class _BidIt> inline 
bool _Next_permutation(_BidIt _First, _BidIt _Last) 
{ // permute and test for pure ascending, using operator< 
_BidIt _Next = _Last; 
if (_First == _Last || _First == --_Next) 
    return (false); 

for (; ;) 
    { // find rightmost element smaller than successor 
    _BidIt _Next1 = _Next; 
    if (_DEBUG_LT(*--_Next, *_Next1)) 
     { // swap with rightmost element that's smaller, flip suffix 
     _BidIt _Mid = _Last; 
     for (; !_DEBUG_LT(*_Next, *--_Mid);) 
     ; 
     _STD iter_swap(_Next, _Mid); 
     _STD reverse(_Next1, _Last); 
     return (true); 
     } 

    if (_Next == _First) 
     { // pure descending, flip all 
     _STD reverse(_First, _Last); 
     return (false); 
     } 
    } 
} 


_Ty operator()() 
    { // return next value 
    static _Ty _Zero = 0; // to quiet diagnostics 
    _Ty _Divisor = (_Ty)_Mx; 

    _Prev = _Mx ? ((_Ity)_Ax * _Prev + (_Ty)_Cx) % _Divisor 
     : ((_Ity)_Ax * _Prev + (_Ty)_Cx); 
    if (_Prev < _Zero) 
     _Prev += (_Ty)_Mx; 
    return (_Prev); 
    } 

कृपया ध्यान दें कि मैं इंटरफ़ेस की आलोचना नहीं कर रहा हूं, क्योंकि यह बहुत अच्छी तरह डिज़ाइन और लागू है। मैं जो चिंतित हूं वह कार्यान्वयन विवरण की पठनीयता है।

ऐसा ही एक सवाल पहले से उत्पन्न किया गया है:

Is there a readable implementation of the STL

Why STL implementation is so unreadable? How C++ could have been improved here?

नोट: ऊपर प्रस्तुत कोड MSVC 2010 एल्गोरिथ्म और कतार हेडर से लिया जाता है।

+1

जैसा कि मैंने इसे पढ़ा है, सवाल वास्तव में नहीं है "एसटीएल इतनी गड़बड़ क्यों है?" लेकिन "एसटीएल के सामान्य रूप से उपयोग किए जाने वाले कार्यान्वयन के कारण इस तरह के स्पष्ट रूप से ठोस स्रोत कोड क्यों हैं?" क्या वो सही है? –

+0

@ जेम्स: यह सही है। मैंने नीचे एक बयान के साथ अपने प्रश्न को और योग्यता प्राप्त की है। –

+2

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

उत्तर

14

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

धारा 17.6.3.3.2 "ग्लोबल नाम" §1 राज्यों:

नाम और समारोह हस्ताक्षर के कुछ सेट हमेशा कार्यान्वयन के लिए आरक्षित हैं:

  • प्रत्येक नाम है कि एक में शामिल है डबल अंडरस्कोर या एक अंडरस्कोर के साथ शुरू होता है जिसके बाद एक अपरकेस अक्षर किसी भी उपयोग के लिए कार्यान्वयन के लिए आरक्षित होता है।

  • अंडरस्कोर से शुरू होने वाला प्रत्येक नाम वैश्विक नामस्थान में नाम के रूप में उपयोग के लिए कार्यान्वयन के लिए आरक्षित है।

कारण के लिए (ध्यान दें कि इन नियमों __MY_FILE_H तरह हैडर गार्ड जो मैं अक्सर देखा है न करे।)

+0

@peoro कहा जाता है, नामस्थान नहीं कक्षा के भीतर चर के लिए मदद करें। –

+6

@peoro नामस्थान प्रीप्रोसेसर मैक्रोज़ से आपकी रक्षा नहीं करते हैं। '_ नाम 'कार्यान्वयन के लिए आरक्षित हैं, इसलिए यदि आपके पास मैक्रोज़ हैं जैसे यह आपके सिर पर है। दूसरी तरफ, आपको यह अनुमान लगाने के लिए मजबूर नहीं किया जाना चाहिए कि एसटीएल कार्यान्वयन आंतरिक रूप से पहचानकर्ता का उपयोग करने का निर्णय ले सकता है कि आपको मैक्रो नहीं बनाना चाहिए, विशेष रूप से यह कार्यान्वयन से कार्यान्वयन में भिन्न हो सकता है। –

+0

आप सही हैं। मैंने "मैक्रो" छोड़ा और उपयोगकर्ता चर/कार्यों के बारे में सोचा, जो समझ में नहीं आया। – peoro

9

चर नाम हैं जो इस मानक पुस्तकालय कोड है, और इसके लिए आरक्षित नामों का उपयोग करना हेडर में कार्यान्वयन विवरण। निम्नलिखित चाहिए नहीं मानक पुस्तकालयों को तोड़ने:

#define mid 
#include <algorithm> 

तो मानक पुस्तकालय हेडर एक चर नाम के रूप में mid उपयोग नहीं कर सकते, इसलिए _Mid।एसटीएल अलग था - यह भाषा विनिर्देश का हिस्सा नहीं था, इसे परिभाषित किया गया था "यहां कुछ शीर्षलेख हैं, जैसे आप करेंगे"

दूसरी ओर आपका कोड या मेरा, अमान्य होगा एक चर नाम के रूप में प्रयोग किया जाता है के बाद से _Mid कि एक आरक्षित नाम है - कार्यान्वयन करने के लिए अनुमति दी है:

#define _Mid 

अगर यह यह की तरह लगता है।

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

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

मैं आपको बता दूंगा कि, operator() अधिभार गड़बड़ है। [संपादित करें: मुझे यह मिल गया है, यह एक रैखिक संगत जनरेटर है, जो बहुत सामान्य रूप से किया जाता है, और यदि मॉड्यूलस "0" है तो इसका मतलब है कि अंकगणितीय प्रकार के प्राकृतिक रैपरअराउंड का उपयोग करें।]

+2

लेकिन यह मानक पुस्तकालयों को तोड़ देता है, बेशक यह होगा। जब 'पहले' कुछ भी नहीं बदला जाता है तो वे 'std :: pair' को कैसे परिभाषित कर सकते हैं? –

+0

पीएस मुझे आपका अंक मिलता है, लेकिन यह एक बुरा उदाहरण है :-) –

+0

@ पीटर: डी ओह! मैं एक बेहतर के बारे में सोचूंगा। –

2

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

+6

आप वास्तव में आशावादी कोड लिख सकते हैं और इसे गठबंधन नहीं कर सकते हैं, एसटीएल चारों ओर घूमने वाली लाइब्रेरी की भिन्नताएं हैं। –

+1

@sonicoder, आप कर सकते हैं लेकिन इसका मतलब यह नहीं है कि लोग करते हैं। –

3

कार्यान्वयन अलग-अलग होते हैं। उदाहरण के लिए libc++, आंखों पर बहुत आसान है। यद्यपि अभी भी अंडरस्कोर शोर का थोड़ा सा है। जैसा कि अन्य ने ध्यान दिया है, प्रमुख अंडरस्कोर दुर्भाग्य से आवश्यक हैं।

template <class _Compare, class _BidirectionalIterator> 
bool 
__next_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) 
{ 
    _BidirectionalIterator __i = __last; 
    if (__first == __last || __first == --__i) 
     return false; 
    while (true) 
    { 
     _BidirectionalIterator __ip1 = __i; 
     if (__comp(*--__i, *__ip1)) 
     { 
      _BidirectionalIterator __j = __last; 
      while (!__comp(*__i, *--__j)) 
       ; 
      swap(*__i, *__j); 
      _STD::reverse(__ip1, __last); 
      return true; 
     } 
     if (__i == __first) 
     { 
      _STD::reverse(__first, __last); 
      return false; 
     } 
    } 
} 
+3

वे केवल कंपाइलर विशिष्ट कीवर्ड और मैक्रोज़ वर्ग/संरचना सदस्यों के लिए आवश्यक हैं। यद्यपि सम्मेलन अन्य प्रीपेन्ड और "एम_" या "एम_" या स्थानीय या वैश्विक चर के विपरीत वर्ग सदस्य को दर्शाने के लिए "_" जोड़ना है। –

+0

ठीक है, मुझे लगता है कि सुधार के लिए जगह है :) – ergosys

+1

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

16

नील बटरवर्थ, अब "शीघ्र" सूचीबद्ध, अतः "Is there a readable implementation of the STL?" सवाल करने के लिए अपने जवाब में एक उपयोगी लिंक प्रदान की: यहाँ libc में ++ एक ही समारोह है। उसके जवाब का हवाला देते हुए:

एक किताब सी ++ स्टैंडर्ड टेम्पलेट लायब्रेरी वहाँ है, मूल एसटीएल डिजाइनरों द्वारा सह-लेखन किया Stepanov & ली है, जो एक संभव का वर्णन करता है (पी.जे. Plauger और डेविड Musser के साथ एक साथ) कार्यान्वयन, कोड के साथ पूर्ण - http://www.amazon.co.uk/C-Standard-Template-Library/dp/0134376331 देखें।

उस धागे में अन्य उत्तरों भी देखें।

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

इस प्रकार, समेकन और पठनीयता के बीच प्राकृतिक व्यापार-बिंदु बिंदु "सामान्य" कोड की तुलना में पैमाने के संक्षिप्तता के अंत में कहीं अधिक है।

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

चीयर्स & hth।,

+3

एक उत्कृष्ट लिंक, मैं इसे प्रश्न में जोड़ रहा हूं। +1 –

+1

टकराव एक पहलू है, प्रदर्शन एक और है (जो पठनीयता को भी नुकसान पहुंचा सकता है): लोग हमेशा एसटीएल कार्यान्वयन में संदिग्ध वसा और अक्षमता की शिकायत कर रहे हैं - पिछले कुछ वर्षों में लगभग सभी को दूर कर दिया गया है, लेकिन कभी-कभी व्यापार- पठनीयता और लालित्य में बंद। –

1

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

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