क्या C में दोहराव एक आवश्यक बुराई है?


16

मैं C के लिए नया हूँ, और मैं सोच रहा हूँ कि क्या कोड डुप्लिकेट एक आवश्यक बुराई है जब यह सामान्य डेटा संरचनाओं और C को सामान्य रूप से लिखने की बात आती है?

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

क्या सामान्य कार्यान्वयन एक आदर्श हैं, या क्या आप प्रत्येक उपयोग के मामले के लिए अलग-अलग कार्यान्वयन लिखते हैं?


11
नैतिक विचित्रता जो आप बता रहे हैं, सी। के लिए अद्वितीय नहीं है। अनायास ही, मुझे लगता है कि एक सामान्य कार्यान्वयन बनाने के लिए बार काफी अधिक है, जब तक कि आपके पास इसके लिए एक दर्शक न हो। एक अच्छा सामान्य कार्यान्वयन बनाने के लिए आवश्यक प्रयास की मात्रा बिंदु-समाधान, IME से अधिक है।
रॉबर्ट हार्वे


1
@kevincline: खैर, जावा में जेनरिक है। दी, यह "पर्दे के पीछे आदमी पर ध्यान न दें" प्रकार की जेनरिक है।
रॉबर्ट हार्वे

1
और जेनरिक से पहले, आप ऑब्जेक्ट में पास हो सकते थे और क्रमशः फ्लोट, डबल, इंटीजर और लॉन्ग में पास हो सकते थे।
डैनियल कपलान

3
Deja vu एक कोड गंध-जांच है और DRY के लिए एक प्राथमिकता IMO पर ध्यान देने योग्य सभी सर्वोत्तम प्रथाओं की जड़ में है। लेकिन मैंने ओओपी-उन्मुख भाषाओं में अपने आप को पैर में गोली मार ली है, इसके लिए नकल से बचने की बहुत कोशिश कर रहा हूं। यदि आप एक-दूसरे के लिए असंबंधित चिंताओं को अनावश्यक रूप से नहीं बांध रहे हैं या एक जैसे बनने वाले दो कार्यों के लिए सुगमता को नष्ट कर रहे हैं, तो मैं किसी भी भाषा में वृत्ति के साथ जाऊंगा।
एरिक रेपेन

जवाबों:


27

C से जेनेरिक कोड लिखना मुश्किल हो जाता है। C ++ के विपरीत, जो आपको टेम्प्लेट और वर्चुअल फ़ंक्शंस देता है, C में सामान्य कोड लिखने के लिए केवल 3 तंत्र हैं:

  1. void* संकेत
  2. प्रीप्रोसेसर मैक्रोज़
  3. कार्य बिंदु

void* संकेत आदर्श से बहुत दूर हैं, क्योंकि आप संकलक द्वारा प्रदान की गई सभी प्रकार की सुरक्षा खो देते हैं, जिसके परिणामस्वरूप अमान्य प्रकार के कलाकारों के परिणामस्वरूप हार्ड-टू-डीबग अपरिभाषित व्यवहार हो सकता है।

प्रीप्रोसेसर मैक्रोज़ में अच्छी तरह से उल्लेखित कमियां हैं - प्रीप्रोसेसर विस्तार मूल रूप से संकलन के चरण से पहले होने वाला एक खोज / प्रतिस्थापन तंत्र है, जिसके परिणामस्वरूप हार्ड-टू-डीबग त्रुटियां हो सकती हैं। चापलूसी उदाहरण कुछ इस तरह है: #define add(x) (x+x)जहां xआप कॉल करते हैं तो दो बार वेतन वृद्धि की जा सकती है add(i++)। आप कर सकते हैं टेम्पलेट-शैली जेनेरिक कोड पूरी तरह से सी-मैक्रोज़ का उपयोग करके लिख हैं, लेकिन परिणाम वास्तव में छिपा हुआ है और बनाए रखना मुश्किल है

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

आप सी का उपयोग करके सी में श्रेणी पदानुक्रम भी लागू कर सकते हैं, जैसा कि GLib पुस्तकालय में किया जाता है जो एक सामान्य GObjectआधार वर्ग प्रदान करता है । लेकिन यह void*पॉइंटर्स का उपयोग करने के समान समस्याओं से ग्रस्त है , क्योंकि आपको अभी भी अप-कास्ट और डाउन-कास्ट को संभावित असुरक्षित मैनुअल कास्टिंग पर भरोसा करने की आवश्यकता है।

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


1
बाहरी दोहराव वाली भाषाओं / टूल या शेल स्क्रिप्ट का उपयोग करके या चींटी या ... का उपयोग करके दोहरावदार सी कोड भी उत्पन्न किया जा सकता है ...
Job

यह Google- रुका हुआ रूसी URL क्या है जिसे आपने अपने उत्तर में रखा है? इसमें क्लिक करने से मेरे ब्राउज़र में "ओपन" प्रॉम्प्ट दिखाई देता है। क्या यह सुरक्षित है?
रॉबर्ट हार्वे

2
@RobertHarvey मेरा एंटीवायरस और सुरक्षा स्कैन यह ठीक है। यह एक सी भाषा हैडर फ़ाइल, एक्सटेंशन .h है। यह कानूनी प्रतीत होता है।
maple_shaft

@maple_shaft: ठीक है। मैंने लिंक के चारों ओर Googlization को हटा दिया है।
रॉबर्ट हार्वे

यह सिर्फ एक सादा पाठ है ।h (C- हैडर) फ़ाइल
चार्ल्स सल्विया

15

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

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

5

यह ध्यान देने योग्य है कि कोड दोहराव को कम करने के लिए आपको पूरी तरह से सामान्य समाधान की आवश्यकता नहीं हो सकती है। कभी-कभी साधारण रीफैक्टरिंग और थोड़ा सा सामान्यीकरण पर्याप्त होता है।

व्यापक दर्शकों के लिए एक सामान्यीकृत समाधान लिखते समय, आपको विचार करना होगा:

  1. उपभोक्ता आपके कोड का उपयोग किस उपन्यास तरीके से कर सकते हैं, और आप उन्हें कैसे रोक सकते हैं?
  2. मुझे किन त्रुटियों को पकड़ने की आवश्यकता है? मुझे किन त्रुटियों को नहीं पकड़ना चाहिए ?
  3. एपीआई को कितना मजबूत होना चाहिए? मुझे कितने ओवरलोड प्रदान करने की आवश्यकता है?
  4. मुझे कौन से सुरक्षा उपाय करने होंगे, ताकि कोड का इस्तेमाल बुरे उद्देश्यों के लिए न किया जा सके?

एरिक लिपर्ट ने .NET फ्रेमवर्क कोड में एकल डिज़ाइन निर्णय के बारे में एक पूरा लेख लिखा था । सब सब में, यह अक्सर सिर्फ रिफ्लेक्टर के लिए सरल है।


3

मैं आमतौर पर ग्लिब्स की तरह एक सामान्य कार्यान्वयन का उपयोग करता हूं , फिर अगर कास्टिंग समाप्त हो रहा है तो बहुत अधिक कष्टप्रद है, इसके लिए एक छोटा प्रकार-विशिष्ट आवरण बनाएं। हालांकि, सी में बहुत सी कास्टिंग की उम्मीद है, जैसा void*कि एक सामान्य प्रकार के रूप में उपयोग किया जाता है, इसलिए किसी अन्य भाषा में "गन्दा" क्या माना जाएगा बस विशिष्ट सी है। पर्याप्त रूप से, यह बहुत अधिक प्राकृतिक लगेगा जब आप भाषा में अधिक अनुभव प्राप्त करें।


2
"किसी अन्य भाषा में 'गन्दा' जो माना जाएगा, वह केवल विशिष्ट सी है। पर्याप्त रूप से, यह बहुत अधिक स्वाभाविक लगेगा जब आप भाषा में अधिक अनुभव प्राप्त करेंगे।" हा, हा, हा! सी हमेशा मेरी पसंदीदा भाषाओं में से एक रही है, लेकिन यह अभी भी बहुत मज़ेदार है!
ग्लेनपेटर्सन

0

पुन: प्रयोज्यता का आपका मुद्दा सी के लिए अद्वितीय नहीं है। हालांकि, कुछ उत्कृष्ट और बहुत ही पुन: प्रयोज्य हैशपॉप कार्यान्वयन वहां से बाहर हैं जो आप को बंद कर सकते हैं। लगभग एक या दो दशक से जावा में है: http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html

हैटर सहित सभी जावा संग्रह को पुनरावृत्ति के विचार से छुटकारा पाने के लिए जावा 8 के लिए फिर से लिखा जा रहा है, और इसके बजाय आपको संग्रह में एक समारोह पास करना होगा ताकि यह आंतरिक रूप से पुनरावृत्ति कर सके। समवर्ती कोड लिखने के लिए यह एक बड़ी जीत है - संग्रह आंतरिक रूप से संगामिति का प्रबंधन कर सकता है ताकि ग्राहक को न करना पड़े। कहा कि, अधिकांश प्रोग्रामर का उपयोग फ़ंक्शन पॉइंटर्स पास करने के लिए नहीं किया जाता है। यह एक अच्छा काम करता है जिसमें यह समझाया गया है कि हैशपॉप कहाँ है: http://cr.openjdk.java.net/~briangoetz/lambda/collections-overview.html

स्काला के सिंटैक्स को सी में कुछ इस तरह से अनुवाद करना कठिन हो सकता है, लेकिन यहां एक संग्रह का एक उदाहरण है जो पहले से ही जावा 8 संग्रह का काम करता है - डिफ़ॉल्ट रूप से अपरिवर्तनीय, विभिन्न ट्रैफ़ॉर्मेशन विधियों को प्रदान करना, फ़ंक्शन पॉइंटर्स और अन्य का उपयोग करना आंशिक आवेदन जैसे शांत सामान: http://www.scala-lang.org/api/current/index.html#scala.collection.Map

यदि आप HashMaps और अन्य अधिक उन्नत डेटा संरचनाओं के साथ बहुत कुछ कर रहे हैं, तो आप ऐसी भाषा को देखना चाहते हैं जो उनका समर्थन करती है।

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

मुझे नहीं लगता कि यह कहना बहुत आसान है कि किसी भी समय आप खुद को कोड डुप्लिकेट पाते हैं, आपको एक फ़ंक्शन बनाना चाहिए। अकेले बग जो आप कोड की एक प्रति में ठीक करते हैं और दूसरे नहीं एक फ़ंक्शन बनाने के लिए पर्याप्त हैं।


1
- "मुझे नहीं लगता कि यह कहना बहुत आसान है कि किसी भी समय आप खुद को कोड डुप्लिकेट पाते हैं, आपको एक फ़ंक्शन बनाना चाहिए" - सी में यह एक सरलीकरण है। पूर्णांक, डबल्स और स्ट्रिंग्स के लिए C में एक स्टैक बनाने का प्रयास करें, प्रत्येक डेटा प्रकार के लिए पुश और पॉप फ़ंक्शन को दोहराए बिना।
mike30

@ माइक शून्य बिंदुओं का उपयोग करके संभव नहीं है?
साकिन

@ माइक - अच्छा बिंदु। लेकिन एक प्रति-बिंदु यह होगा कि आप प्रत्येक डेटा प्रकार के लिए स्टैक को इस तरह से लागू कर सकते हैं कि आपको स्टैक को फिर से लागू करने की आवश्यकता न हो। तो लक्ष्य संख्या 1 नहीं है = 1 intकार्यान्वयन , लेकिन अधिक 5 की तरह। आप charएस के लिए कार्यान्वयन कार्य करने में सक्षम हो सकते हैं ... यह बहुत लंबा हो गया है क्योंकि मैंने सी का उपयोग किया है जो मुझे याद नहीं है।
ग्लेनपेटर्सन

1
@faif। हां, लेकिन शून्य बिंदुओं का उपयोग करने की आवश्यकता सी के लिए बिंदु बनाती है। कास्टिंग पॉइंट धीमी और सी ++ में पाए गए विकल्पों की तुलना में कम सुरुचिपूर्ण है। सी में कोडिंग करते समय संभावित विकल्पों की सूची पर कोड को कुछ हद तक
दोहराते हुए

@ mike30 क्या इसके बारे में कोई सबूत / संदर्भ हैं: "C में कास्टिंग पॉइंट्स C ++ में पाए गए विकल्पों की तुलना में धीमा है?"
सकिस्क

0

मैं सोच रहा था कि जब सामान्य डेटा संरचनाओं और C को सामान्य रूप से लिखने की बात आती है तो कोड दोहराव एक आवश्यक बुराई है?

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

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

उदाहरण के लिए, मैंने संभवतः इस मूल "अनुक्रमित नि: शुल्क सूची" डेटा संरचना को स्थानीय रूप से C में एक दर्जन बार प्रत्येक साइट के लिए लागू किया है जो इस आवंटन रणनीति का उपयोग करता है (एक समय में एक नोड आवंटित करने से बचने के लिए और मेमोरी को आधा करने के लिए मेरी सभी लिंक की गई संरचनाएं 64-बिट पर लिंक की लागत):

यहाँ छवि विवरण दर्ज करें

लेकिन C में यह एक बहुत ही कम मात्रा में कोड को reallocएक विकसित करने योग्य सरणी में ले जाता है और एक नई डेटा संरचना को लागू करते समय एक मुक्त सूची में अनुक्रमित दृष्टिकोण का उपयोग करके इसमें से कुछ मेमोरी को पूल करता है।

अब मेरे पास C ++ में लागू की गई एक ही चीज है और वहां मैंने केवल एक बार क्लास टेम्पलेट के रूप में इसे लागू किया है। लेकिन यह कोड की सैकड़ों लाइनों और कुछ बाहरी निर्भरताओं के साथ C ++ पक्ष पर एक बहुत अधिक जटिल कार्यान्वयन है, जो कोड की सैकड़ों लाइनों को भी फैलाता है। और मुख्य कारण यह बहुत अधिक जटिल है क्योंकि मुझे इसे उस विचार के खिलाफ कोड करना Tहोगा जो किसी भी संभव डेटा प्रकार का हो सकता है। यह किसी भी समय फेंक सकता है (इसे नष्ट करने के अलावा, जो मुझे मानक पुस्तकालय कंटेनरों के साथ स्पष्ट रूप से करना है), मुझे स्मृति को आवंटित करने के लिए उचित संरेखण के बारे में सोचना थाT (हालांकि सौभाग्य से यह C ++ 11 बाद में आसान हो गया है), यह गैर-तुच्छ रूप से रचनात्मक / विनाशकारी हो सकता है (प्लेसमेंट नए और मैनुअल डोर इनवोकेशन की आवश्यकता होती है), मुझे ऐसे तरीकों को जोड़ना होगा, जिसमें हर चीज की आवश्यकता नहीं होगी - इन चीजों की आवश्यकता होगी, और मुझे पुनरावृत्तियों को जोड़ना होगा, दोनों उत्परिवर्तनीय और केवल-पढ़ने (कास्ट) पुनरावृत्तियों, और इसी तरह और आगे।

बढ़ते एरर रॉकेट साइंस नहीं हैं

C ++ में लोग इसे साउंड बनाते हैं जैसे std::vectorकि रॉकेट वैज्ञानिक का काम है, मृत्यु के अनुकूल, लेकिन यह किसी विशिष्ट डेटा प्रकार के खिलाफ कोडित डायनामिक C सरणी से बेहतर प्रदर्शन नहीं करता है, जो सिर्फ reallocपुश बैक पर सरणी क्षमता बढ़ाने के लिए उपयोग करता है कोड की दर्जन लाइनें। अंतर यह है कि यह मानक के साथ सिर्फ एक विकसित यादृच्छिक-अभिगम अनुक्रम को पूरी तरह से अनुपालन करने के लिए एक बहुत ही जटिल कार्यान्वयन लेता है, असिंचित तत्वों पर ctors को आमंत्रित करने से बचें, अपवाद-सुरक्षित, दोनों कांस्ट और गैर-कॉन्स्टैंट रैंडम-एक्सेस पुनरावृत्तियों प्रदान करते हैं, प्रकार का उपयोग करते हैं कुछ अभिन्न प्रकारों के लिए रेंज सेटर्स से भराव को रोकने के लिए लक्षणTसंभावित रूप से PODs का उपयोग विभिन्न प्रकार के लक्षणों, इत्यादि इत्यादि के बारे में करें। उस बिंदु पर, जो आप करते हैं, वास्तव में, एक बहुत ही महत्वपूर्ण कार्यान्वयन की जरूरत है, ताकि एक गतिशील गतिशील सरणी बनाई जा सके, लेकिन केवल इसलिए कि यह हर संभव उपयोग के मामले को कभी कल्पना करने योग्य बनाने की कोशिश कर रहा है। प्लस साइड पर, आप पूरी तरह से बहुत सारा माइलेज प्राप्त कर सकते हैं, यदि आप पीयूडी और गैर-तुच्छ यूडीटी दोनों को स्टोर करने के लिए अतिरिक्त प्रयास करते हैं, तो किसी भी आज्ञाकारी डेटा संरचना पर जेनेरिक इट्रेटर-आधारित एल्गोरिदम का उपयोग करें। अपवाद-हैंडलिंग और RAII से लाभ, कम से कम कभी-कभी ओवरराइडstd::allocatorअपने स्वयं के कस्टम आवंटनकर्ता इत्यादि के साथ, यह निश्चित रूप से मानक पुस्तकालय में भुगतान करता है जब आप विचार करते हैं कि कितना लाभ हुआstd::vector पूरी दुनिया के उन लोगों पर पड़ा है जिन्होंने इसका उपयोग किया है, लेकिन यह पूरी दुनिया की जरूरतों को लक्षित करने के लिए डिज़ाइन किए गए मानक पुस्तकालय में लागू कुछ के लिए है।

बहुत ही विशिष्ट उपयोग मामलों को संभालने वाले सरल कार्यान्वयन

मेरी नि: शुल्क सूची के साथ बहुत विशिष्ट उपयोग के मामलों को संभालने के परिणामस्वरूप, इस नि: शुल्क सूची को सी साइड पर एक दर्जन बार लागू करने और परिणामस्वरूप कुछ तुच्छ कोड होने के बावजूद, मैंने शायद कम कोड लिखा है C को लागू करने के लिए कुल C कि मुझे C ++ में सिर्फ एक बार लागू करने की तुलना में एक दर्जन बार, और मुझे उस C C कार्यान्वयन को बनाए रखने की तुलना में उन दर्जन सी कार्यान्वयन को बनाए रखने में कम समय बिताना पड़ा। सी साइड होने का एक मुख्य कारण यह है कि मैं आमतौर पर C में POD के साथ काम कर रहा हूं जब भी मैं इस तकनीक का उपयोग करता हूं और मुझे आमतौर पर इससे अधिक कार्यों की आवश्यकता नहीं होती हैinsert औरeraseजिन विशिष्ट साइटों पर मैं इसे स्थानीय स्तर पर लागू करता हूं। मूल रूप से मैं कार्यक्षमता का सबसे छोटा सबसेट लागू कर सकता हूं, जो C ++ संस्करण प्रदान करता है, क्योंकि मैं जो कुछ करता हूं उसके बारे में बहुत अधिक धारणाएं बनाने के लिए स्वतंत्र हूं और जब मैं इसे बहुत विशिष्ट उपयोग के लिए लागू कर रहा हूं तो मुझे डिजाइन की आवश्यकता नहीं है। मामला।

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

C ++ पर हमला नहीं!

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

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

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

लेकिन वैसे भी, मैं दोनों भाषाओं से प्यार करता हूं, लेकिन अलग-अलग प्रवृत्तियां हैं। सीआई में पर्याप्त सामान्यीकरण न करने की प्रवृत्ति होती है। C ++ में मेरे पास बहुत अधिक सामान्य करने की प्रवृत्ति है। दोनों का उपयोग करने से मुझे खुद को संतुलित करने में मदद मिली।

क्या सामान्य कार्यान्वयन एक आदर्श हैं, या क्या आप प्रत्येक उपयोग के मामले के लिए अलग-अलग कार्यान्वयन लिखते हैं?

एकल या एक सरणी से नोड्स का उपयोग करके 32-बिट अनुक्रमित सूचियों जैसी तुच्छ चीजों के लिए std::vector, जो वास्तविक रूप से स्वयं ( सी ++ में समतुल्य समतुल्य ) का उपयोग करता है या, कहो, एक ऑक्ट्री जो केवल अंकों को संग्रहीत करती है और कुछ भी नहीं करने का लक्ष्य रखती है, मैं डॉन ' किसी भी प्रकार के डेटा को संग्रहीत करने के बिंदु पर सामान्यीकरण करने की जहमत नहीं उठानी चाहिए। मैं इन्हें एक विशिष्ट डेटा प्रकार को स्टोर करने के लिए कार्यान्वित करता हूं (हालांकि यह सार हो सकता है और कुछ मामलों में फ़ंक्शन पॉइंटर्स का उपयोग कर सकता है, लेकिन स्थिर बहुरूपता के साथ बतख टाइपिंग की तुलना में कम से कम अधिक विशिष्ट है)।

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

Nontrivial चीजों के लिए, यह आमतौर पर तब होता है जब मैं C ++ के लिए पहुंचता हूं, लेकिन अगर मैं इसे C में लागू करने वाला था, तो मैं सिर्फ void*पॉइंटर्स का उपयोग करने पर विचार करूंगा, शायद यह जानने के लिए कि कोई मेमोरी कितने एलिमेंट को एलिमेंट करने के लिए एक टाइप साइज स्वीकार करती है, और संभवतः copy/destroyफंक्शन पॉइंटर्स यदि यह तुच्छ रूप से रचनात्मक / विनाशकारी नहीं है, तो डेटा की प्रतिलिपि बनाएँ और नष्ट करें। सबसे अधिक बार मैं परेशान नहीं करता हूं और सबसे जटिल डेटा संरचनाओं और एल्गोरिदम को बनाने के लिए बहुत सी का उपयोग नहीं करता हूं।

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

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

हैश टेबल एक प्रकार की iffy हैं क्योंकि इसे लागू करना या वास्तव में जटिल हो सकता है यह इस बात पर निर्भर करता है कि आपकी ज़रूरतें हैश, रिहैसेस के संबंध में कितनी जटिल हैं, यदि आपको स्वचालित रूप से टेबल को अपने अनुमानित रूप से विकसित करने की आवश्यकता है या तालिका आकार का अनुमान लगा सकते हैं। एडवांस, चाहे आप ओपन एड्रेसिंग या अलग चैनिंग आदि का उपयोग करें, लेकिन एक बात का ध्यान रखें कि यदि आप किसी विशिष्ट साइट की जरूरतों के लिए हैश टेबल को पूरी तरह से सिल लेते हैं, तो यह अक्सर कार्यान्वयन में इतना जटिल नहीं होगा और अक्सर जीता जाता है। जब यह उन जरूरतों के लिए ठीक सिलवाया जाता है तो बेमानी न हों। कम से कम यही बहाना तो मैं खुद देता हूं अगर मैं स्थानीय स्तर पर कुछ लागू करता हूं। यदि नहीं, तो आप void*चीजों को कॉपी / नष्ट करने और इसे सामान्य बनाने के लिए ऊपर वर्णित विधि का उपयोग कर सकते हैं ।

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

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

सजातीय बिट्स और बाइट्स

सी में शोषण करने के लिए एक चीज क्योंकि इसमें प्रकार की सुरक्षा की एक अंतर्निहित कमी है, यह बिट्स और बाइट्स की विशेषताओं के आधार पर सजातीय चीजों को संग्रहीत करने का विचार है। स्मृति आबंटक और डेटा संरचना के बीच एक धब्बा के रूप में वहाँ अधिक है।

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

तो सी में उपयोग करने के लिए एक रणनीति, हालांकि यह कम प्रकार की समृद्धि और सुरक्षा पर आती है, बिट्स और बाइट्स के स्तर पर सामान्यीकरण करना है। आपको लगता है कि ग्रहण करने के लिए सक्षम हो सकता है Dogsऔर Catsबिट्स और बाइट्स की एक ही नंबर की आवश्यकता होती है, उसी के मैदान, एक समारोह सूचक तालिका के लिए एक ही सूचक है। लेकिन बदले में आप कम डेटा संरचनाओं को कोड कर सकते हैं, लेकिन जैसा कि महत्वपूर्ण है, इन सभी चीजों को कुशलतापूर्वक और संयोग से स्टोर करें। आप उस मामले में एनालॉग यूनियनों की तरह कुत्तों और बिल्लियों का इलाज कर रहे हैं (या आप वास्तव में एक संघ का उपयोग कर सकते हैं)।

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

भ्रम / स्पष्ट दोहराव

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

का उपयोग कर realloc, एक साधारण बढ़ने योग्य सरणी कार्यान्वयन ले , के समतुल्य समकक्ष std::vector<int>। प्रारंभ में, यह std::vector<int>C ++ में उपयोग के साथ बेमानी हो सकता है। लेकिन, आप माप के माध्यम से पा सकते हैं कि, पहले से ही 64 बाइट्स का प्रचार करना फायदेमंद हो सकता है ताकि ढेर आवंटन की आवश्यकता के बिना सोलह 32-बिट पूर्णांक डालने की अनुमति दी जा सके। अब यह बेमानी नहीं है, कम से कम साथ नहीं std::vector<int>। और फिर आप कह सकते हैं, "लेकिन मैं इसे एक नए रूप में सामान्य कर सकता हूं।"SmallVector<int, 16> , और आप कर सकते हैं। लेकिन फिर मान लें कि यह आपको उपयोगी लगता है क्योंकि ये बहुत ही छोटे, अल्पकालिक सरणियों के लिए हैं, बजाय ढेर आवंटन पर सरणी क्षमता को चौगुनी करने के लिए 1.5 से बढ़ रही है (लगभग राशि है कि कईvectorकार्यान्वयन का उपयोग करते हुए) इस धारणा से काम करते हुए कि सरणी क्षमता हमेशा दो की शक्ति होती है। अब आपका कंटेनर वास्तव में अलग है, और शायद ऐसा कोई कंटेनर नहीं है। और हो सकता है कि आप प्रचार-प्रसार भारी, कस्टमाइज़ेशन व्यवहार, आदि को अनुकूलित करने के लिए अधिक से अधिक टेम्पलेट मापदंडों को जोड़कर इस तरह के व्यवहारों को सामान्य बनाने की कोशिश कर सकते हों, लेकिन उस बिंदु पर आपको साधारण सी की एक दर्जन लाइनों की तुलना में वास्तव में उपयोग में न आने वाली कुछ चीजें मिल सकती हैं। कोड।

और आप उस बिंदु पर भी पहुंच सकते हैं, जहां आपको एक डेटा संरचना की आवश्यकता होती है, जो 256-बिट संरेखित और गद्देदार स्मृति को आवंटित करता है, AVX 256 निर्देशों के लिए विशेष रूप से PODs का भंडारण करता है, आम मामला छोटे इनपुट आकार के लिए ढेर आवंटन से बचने के लिए 128 बाइट्स का प्रचार करता है, जब क्षमता में दोगुना हो जाता है। पूर्ण, और सरणी आकार से अधिक नहीं बल्कि सरणी क्षमता से अधिक होने वाले तत्वों के सुरक्षित अधिलेखित करने की अनुमति देता है। उस बिंदु पर यदि आप अभी भी सी कोड की एक छोटी मात्रा को डुप्लिकेट से बचने के लिए एक समाधान को सामान्य बनाने की कोशिश कर रहे हैं, तो प्रोग्रामिंग देवताओं को आपकी आत्मा पर दया आ सकती है।

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

PODs और आदिम

अब C में, मैं अक्सर PODs और विशेष रूप से आदिम को डेटा संरचनाओं में संग्रहीत करने के लिए बहाने ढूंढता हूं जब भी संभव हो। यह एक विरोधी पैटर्न की तरह लग सकता है, लेकिन मैंने वास्तव में इसे अनजाने में उन चीजों के प्रकारों पर कोड की स्थिरता को सुधारने में मददगार पाया है जो मैं सी ++ में अधिक बार करता था।

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

struct IternedString 
{
    int32_t index;
};

... हमारे हैश टेबल में, लाल-काले पेड़, सूची छोड़ें, आदि, अगर हमें लेक्सोग्राफिक छंटाई की आवश्यकता नहीं है? अब हमारी सभी अन्य डेटा संरचनाएं जिन्हें हमने 32-बिट पूर्णांक के साथ काम करने के लिए कोडित किया था, अब इन इंटर्न स्ट्रिंग स्ट्रिंग को संग्रहीत कर सकते हैं जो प्रभावी रूप से सिर्फ 32-बिट हैं ints। और मैंने अपने उपयोग के मामलों में कम से कम पाया है (मैं सिर्फ मेरा डोमेन हो सकता हूं क्योंकि मैं रेस्ट्रिंग, मेष प्रसंस्करण, छवि प्रसंस्करण, कण प्रणाली जैसे क्षेत्रों में काम करता हूं, स्क्रिप्टिंग भाषाओं के लिए बाध्य हूं, निम्न-स्तरीय मल्टीथ्रेडेड GUI किट कार्यान्वयन, आदि)। निम्न-स्तरीय चीजें लेकिन एक OS के रूप में निम्न-स्तर नहीं), कि संयोग से कोड अधिक कुशल और सरल हो जाता है जैसे कि इस तरह की चीजों के लिए सूचकांकों को संग्रहीत करना। ऐसा लगता है कि मैं अक्सर काम कर रहा हूँ, बस int32_tऔर के साथ, समय का 75% कहते हैंfloat32 मेरी गैर-तुच्छ डेटा संरचनाओं में, या केवल एक ही आकार वाली चीजें (लगभग हमेशा 32-बिट) संग्रहीत करने के लिए।

और स्वाभाविक रूप से यदि यह आपके मामले के लिए लागू होता है, तो आप विभिन्न डेटा प्रकारों के लिए कई डेटा संरचना कार्यान्वयन होने से बच सकते हैं, क्योंकि आप पहली बार इतने कम काम कर रहे होंगे।

परीक्षण और विश्वसनीयता

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

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

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

मिनिमलिज़्म के लिए कोड दोहराव?

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

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

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

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