क्या C ++ की तुलना में C # आपको "खुद को लटकाने के लिए कम रस्सी" देता है? [बन्द है]


14

जोएल स्पोल्स्की ने C ++ को "अपने आप को लटकाने के लिए पर्याप्त रस्सी" के रूप में विशेषता दी । वास्तव में, वह स्कॉट मेयर्स द्वारा "प्रभावी सी ++" का सारांश दे रहा था:

यह एक किताब है जो मूल रूप से कहती है, सी ++ अपने आप को फांसी देने के लिए पर्याप्त रस्सी है, और फिर रस्सी के अतिरिक्त मील की एक जोड़ी है, और फिर आत्महत्या की गोलियाँ जो एम एंड एमएस के रूप में प्रच्छन्न हैं ...

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

यहाँ मेरे सवाल हैं:

  1. क्या C # उन सावधानियों से बचता है जिन्हें C ++ में केवल सावधानीपूर्वक प्रोग्रामिंग से बचा जाता है? यदि हां, तो उन्हें किस डिग्री और कैसे टाला जाता है?
  2. क्या C # में नए, अलग-अलग नुकसान हो सकते हैं, जो एक नए C # प्रोग्रामर को पता होना चाहिए? यदि हां, तो उन्हें C # के डिजाइन से क्यों नहीं रोका जा सकता है?

10
से पूछे जाने वाले प्रश्न : Your questions should be reasonably scoped. If you can imagine an entire book that answers your question, you’re asking too much.। मेरा मानना ​​है कि यह इस तरह के एक प्रश्न के रूप में उत्तीर्ण होता है ...
ऊद

@ क्या आप चरित्र-सीमित शीर्षक प्रश्न का संदर्भ दे रहे हैं? या मेरे पोस्ट के शरीर में मेरे 3+ अधिक सटीक प्रश्न?
alx9r

3
सच कहूं - दोनों शीर्षक और प्रत्येक "और अधिक सटीक सवाल" की।
ऊद

3
मैंने इस प्रश्न के बारे में एक मेटा चर्चा शुरू की है ।
ओड

1
आपके अब हटाए गए 3 प्रश्न के बारे में, बिल वैग्नर की प्रभावी सी # श्रृंखला (अब 3 किताबें) ने मुझे प्रोग्रामिंग सी # के बारे में और अधिक पढ़ाया, जो मैंने इस विषय पर पढ़ी गई किसी भी चीज़ से अधिक है। EC # की मार्टिंस समीक्षा इस बात में सही है कि यह प्रभावी C ++ के लिए प्रत्यक्ष प्रतिस्थापन नहीं हो सकता है, लेकिन वह गलत सोच है कि यह होना चाहिए। एक बार जब आपको आसान गलतियों के बारे में चिंता करने की ज़रूरत नहीं है, तो आपको कठिन गलतियों पर आगे बढ़ना होगा ।
मार्क बूथ 13

जवाबों:


33

C ++ और C # के बीच मूलभूत अंतर अपरिभाषित व्यवहार से उपजा है

इसका मैनुअल मेमोरी मैनेजमेंट करने से कोई लेना- देना नहीं है। दोनों ही मामलों में, यह एक सुलझी हुई समस्या है।

C / C ++:

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

शायद अपरिभाषित व्यवहार पर इस 3-भाग श्रृंखला को पढ़ें

यह वही है जो C ++ को इतनी तेजी से बनाता है - कंपाइलर को इस बारे में चिंता करने की आवश्यकता नहीं है कि जब चीजें गलत होती हैं, तो यह शुद्धता के लिए जाँच से बच सकता है।

सी #, जावा, आदि।

C # में, आपको गारंटी दी जाती है कि अपवाद के रूप में आपके चेहरे पर कई गलतियाँ होंगी, और आप अंतर्निहित सिस्टम के बारे में बहुत अधिक गारंटी देते हैं ।
यह C # को C ++ जितना तेज बनाने के लिए एक मूलभूत बाधा है, लेकिन C ++ को सुरक्षित बनाने के लिए यह एक मूलभूत बाधा भी है, और यह C # को आसान बनाने और डिबग करने में आसान बनाता है।

बाकी सब सिर्फ ग्रेवी है।


सभी अपरिभाषित सामान वास्तव में कार्यान्वयन द्वारा परिभाषित किए गए हैं, इसलिए यदि आप विज़ुअल स्टूडियो में एक अहस्ताक्षरित पूर्णांक को ओवरफ्लो करते हैं, तो आपको एक कंपाइलर मिलेगा यदि आपने सही कंपाइलर झंडे को चालू किया है। अब मुझे पता है कि यह आप किस बारे में बात कर रहे हैं, लेकिन यह अपरिभाषित व्यवहार नहीं है , बस इसके लोग आमतौर पर इसके लिए जांच नहीं करते हैं। (ऑपरेटर ++ जैसे वास्तव में अपरिभाषित व्यवहार के साथ, यह प्रत्येक संकलक द्वारा अच्छी तरह से परिभाषित किया गया है)। आप सी # के साथ भी ऐसा ही कह सकते हैं, केवल 1 कार्यान्वयन है - 'अपराजित व्यवहार' के बहुत सारे अगर आप मोनोर में चलते हैं - जैसे। Bugzilla.xamarin.com/show_bug.cgi?id=310
gbjbaanb

1
क्या यह वास्तव में परिभाषित है या केवल विंडोज के वर्तमान संस्करण पर वर्तमान .net कार्यान्वयन जो कुछ भी करता है, उसी से परिभाषित होता है? यहां तक ​​कि c ++ अपरिभाषित व्यवहार भी पूरी तरह से परिभाषित है यदि आप इसे परिभाषित करते हैं जैसे कि जी ++ करता है।
मार्टिन बेकेट

6
अहस्ताक्षरित पूर्णांक ओवरफ्लो करना यूबी बिलकुल भी नहीं है। यह यूबी है कि हस्ताक्षरित पूर्णांक से अधिक बह रहा है ।
डेडएमजी

6
@gbjbaanb: जैसे DeadMG कहा - पर हस्ताक्षर किए पूर्णांक अतिप्रवाह है अपरिभाषित। यह नहीं कार्यान्वयन से परिभाषित। उन वाक्यांशों का C ++ मानक में विशिष्ट अर्थ है, और वे एक ही बात नहीं हैं। वह गलती मत करो।
user541686

1
@CharlesSalvia: उह, वास्तव में "C ++ से सीपीयू कैश" का लाभ लेना कितना आसान हो जाता है? और C ++ किस तरह का नियंत्रण आपको स्मृति पर देता है जो आपके C # में नहीं हो सकता है?
user541686

12

क्या C # उन सावधानियों से बचता है जिन्हें C ++ में केवल सावधानीपूर्वक प्रोग्रामिंग से बचा जाता है? यदि हां, तो उन्हें किस डिग्री और कैसे टाला जाता है?

अधिकांश यह करता है, कुछ यह नहीं करता है। और हां, यह कुछ नया बनाता है।

  1. अपरिभाषित व्यवहार - C ++ के साथ सबसे बड़ा नुकसान यह है कि भाषा की एक पूरी बहुत कुछ है जो अपरिभाषित है। कंपाइलर सचमुच ब्रह्मांड को उड़ा सकता है जब आप इन चीजों को करते हैं, और यह ठीक होगा। स्वाभाविक रूप से, यह असामान्य है, लेकिन यह है एक मशीन पर और वास्तव में कोई अच्छा कारण दूसरे पर काम नहीं करने के लिए काम ठीक करने के लिए अपने कार्यक्रम के लिए बहुत आम है। या इससे भी बदतर, आसानी से अलग कार्य करते हैं। C # के विनिर्देशन में अपरिभाषित व्यवहार के कुछ मामले हैं, लेकिन वे दुर्लभ हैं, और भाषा के उन क्षेत्रों में जो अक्सर यात्रा की जाती हैं। हर बार जब आप कोई वक्तव्य देते हैं, तो C ++ के अपरिभाषित व्यवहार में चलने की संभावना होती है।

  2. मेमोरी लीक्स - यह आधुनिक C ++ के लिए एक चिंता का विषय है, लेकिन शुरुआती लोगों के लिए और अपने जीवनकाल के आधे के दौरान, C ++ ने मेमोरी को लीक करना आसान बना दिया। प्रभावी C ++ इस चिंता को खत्म करने के लिए प्रथाओं के विकास के आसपास आया। उस ने कहा, C # अभी भी मेमोरी लीक कर सकता है । लोगों द्वारा चलाए जा रहे सबसे आम मामले ईवेंट कैप्चर हैं। यदि आपके पास कोई वस्तु है, और उसके किसी तरीके को एक घटना के लिए एक हैंडलर के रूप में डालते हैं, तो उस घटना के मालिक को ऑब्जेक्ट को मरने के लिए GC'd होना चाहिए। अधिकांश शुरुआती यह महसूस नहीं करते हैं कि घटना हैंडलर संदर्भ के रूप में गिना जाता है। डिस्पोजेबल संसाधनों का निपटान नहीं करने के मुद्दे भी हैं जो मेमोरी को लीक कर सकते हैं, लेकिन ये पूर्व-प्रभावी सी ++ में संकेत के रूप में लगभग आम नहीं हैं।

  3. संकलन - C ++ में एक मंद संकलन मॉडल है। यह इसके साथ अच्छा खेलने के लिए कई ट्रिक्स की ओर जाता है, और संकलन समय को नीचे रखता है।

  4. स्ट्रिंग्स - आधुनिक सी ++ इसे थोड़ा बेहतर बनाता है, लेकिन char*वर्ष 2000 से पहले सभी सुरक्षा उल्लंघनों के ~ 95% के लिए जिम्मेदार है। अनुभवी प्रोग्रामर के लिए, वे ध्यान केंद्रित करेंगे std::string, लेकिन पुराने और बदतर पुस्तकालयों में समस्या से बचने के लिए यह अभी भी कुछ है। । और यह प्रार्थना है कि आपको यूनिकोड समर्थन की आवश्यकता नहीं है।

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

क्या C # में नए, अलग-अलग नुकसान हो सकते हैं, जो एक नए C # प्रोग्रामर को पता होना चाहिए? यदि हां, तो C # के डिजाइन से वे क्यों नहीं बच सकते?

मैंने घटना "मेमोरी लीक" मुद्दे का उल्लेख किया। यह एक भाषा की समस्या नहीं है, क्योंकि प्रोग्रामर कुछ ऐसी उम्मीद करता है जो भाषा नहीं कर सकती है।

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

एक और अर्ध-गड्ढा मैंने देखा है कि प्रोग्रामर रन करते हैं अनाम कार्यों के कैप्चर शब्दार्थ। जब आप एक चर पर कब्जा करते हैं, तो आप चर पर कब्जा कर लेते हैं । उदाहरण:

List<Action> actions = new List<Action>();
for(int x = 0; x < 10; ++x ){
    actions.Add(() => Console.WriteLine(x));
}

foreach(var action in actions){
    action();
}

भोलेपन से जो सोचा जाता है वह नहीं करता। यह 1010 बार प्रिंट करता है।

मुझे यकीन है कि मैं दूसरों को भूल रहा हूं, लेकिन मुख्य मुद्दा यह है कि वे कम विकृत हैं।


4
मेमोरी लीक अतीत की बात है, और ऐसा ही है char*। यह उल्लेख करने के लिए नहीं कि आप अभी भी C # ठीक में मेमोरी को लीक कर सकते हैं।
डेडएमजी

2
कॉलिंग टेम्प्लेट "महिमा स्ट्रिंग चिपकाना" थोड़ा अधिक है। टेम्प्लेट वास्तव में C ++ की सर्वश्रेष्ठ विशेषताओं में से एक हैं।
चार्ल्स साल्विया

2
@CharlesSalvia ज़रूर, वे कर रहे हैं सी ++ का वास्तव में ख़ास विशेषता। और हाँ, यह शायद संकलन प्रभाव के लिए एक निरीक्षण है। लेकिन वे असंगत रूप से संकलन समय और आउटपुट आकार को प्रभावित करते हैं, खासकर यदि आप सावधान नहीं हैं।
तेलस्टिन

2
@deadMG निश्चित रूप से, हालांकि मैं तर्क दूंगा कि C ++ में उपयोग किए जाने वाले / आवश्यक कई टेम्प्लेट मेटा-प्रोग्रामिंग ट्रिक्स हैं ... बेहतर तरीके से एक अलग तंत्र के माध्यम से कार्यान्वित किए जाते हैं।
तेलस्टिन

2
@Telastyn का पूरा बिंदु type_traits संकलन समय पर टाइप जानकारी प्राप्त करने के लिए है, इसलिए आप इस जानकारी का उपयोग विशिष्ट तरीके से टेम्पलेट या अधिभार कार्यों की तरह काम करने के लिए कर सकते हैंenable_if
चार्ल्स साल्विया

10

मेरी राय में, C ++ के खतरे कुछ हद तक अतिरंजित हैं।

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

यह "अतिरिक्त रस्सी", इसलिए बोलने के लिए, जोएल स्पोल्स्की के बारे में बात कर रहा था , मूल रूप से एक चीज़ के लिए नीचे आता है: लेखन कक्षाएं जो आंतरिक रूप से अपनी स्मृति का प्रबंधन करती हैं, जिसे " नियम 3 " के रूप में भी जाना जाता है (जिसे अब नियम कहा जा सकता है) 4 का नियम या C ++ 11 में 5 का नियम)। इसका मतलब है, यदि आप कभी भी एक वर्ग लिखना चाहते हैं जो आंतरिक रूप से अपने स्वयं के मेमोरी आवंटन का प्रबंधन करता है, तो आपको यह जानना होगा कि आप क्या कर रहे हैं या अन्यथा आपका कार्यक्रम दुर्घटनाग्रस्त हो जाएगा। आपको सावधानी से एक कंस्ट्रक्टर, कॉपी कंस्ट्रक्टर, डिस्ट्रक्टर, और असाइनमेंट ऑपरेटर बनाना होगा, जो आश्चर्यजनक रूप से गलत होने में आसान है, जिसके परिणामस्वरूप रनटाइम के दौरान अक्सर विचित्र दुर्घटनाएं होती हैं।

हालांकि , में वास्तविक हर दिन C ++ प्रोग्रामिंग, यह बहुत ही दुर्लभ वास्तव में तो यह कहना है कि सी ++ प्रोग्रामर हमेशा "सावधान" इन नुकसान से बचने के लिए होने की जरूरत को गुमराह कर रहा है, एक वर्ग है कि अपनी ही स्मृति का प्रबंधन करता है लिखने के लिए। आमतौर पर, आप बस कुछ और कर रहे होंगे जैसे:

class Foo
{
    public:

    Foo(const std::string& s) 
        : m_first_name(s)
    { }

    private:

    std::string m_first_name;
};

यह वर्ग जावा या C # में आपके द्वारा किए गए कार्यों के बहुत करीब दिखता है - इसके लिए किसी स्पष्ट मेमोरी प्रबंधन की आवश्यकता नहीं होती है (क्योंकि पुस्तकालय वर्ग std::stringसभी का ध्यान रखता है), और डिफ़ॉल्ट रूप से सभी पर "3 नियम" सामान की आवश्यकता नहीं है कॉपी कंस्ट्रक्टर और असाइनमेंट ऑपरेटर ठीक है।

यह केवल तभी होता है जब आप कुछ करने की कोशिश करते हैं:

class Foo
{
    public:

    Foo(const char* s)
    { 
        std::size_t len = std::strlen(s);
        m_name = new char[len + 1];
        std::strcpy(m_name, s);
    }

    Foo(const Foo& f); // must implement proper copy constructor

    Foo& operator = (const Foo& f); // must implement proper assignment operator

    ~Foo(); // must free resource in destructor

    private:

    char* m_name;
};

इस मामले में, नौसिखियों के लिए असाइनमेंट, डिस्ट्रॉक्टर और कॉपी कंस्ट्रक्टर को सही करना मुश्किल हो सकता है। लेकिन ज्यादातर मामलों में, ऐसा करने का कोई कारण नहीं है। C ++ लाइब्रेरी कक्षाओं जैसे std::stringऔर का उपयोग करके मैन्युअल मेमोरी मैनेजमेंट को 99% समय से बचना बहुत आसान बनाता है std::vector

एक अन्य संबंधित मुद्दा मैन्युअल रूप से मेमोरी को प्रबंधित करना है जो अपवाद को फेंकने की संभावना को ध्यान में नहीं रखता है। पसंद:

char* s = new char[100];
some_function_which_may_throw();
/* ... */
delete[] s;

यदि some_function_which_may_throw()वास्तव में कोई अपवाद नहीं छोड़ता है, तो आप एक मेमोरी लीक के साथ छोड़ दिए जाते हैं क्योंकि इसके लिए आवंटित मेमोरी sको कभी भी पुनः प्राप्त नहीं किया जाएगा। लेकिन फिर, व्यवहार में यह शायद ही किसी और कारण के लिए एक मुद्दा है कि "3 का नियम" वास्तव में अब कोई समस्या नहीं है। यह बहुत दुर्लभ है (और आमतौर पर अनावश्यक) वास्तव में कच्चे पॉइंटर्स के साथ अपनी स्मृति का प्रबंधन करने के लिए। उपरोक्त समस्या से बचने के लिए, आपको केवल एक std::stringया एक का उपयोग std::vectorकरना होगा, और अपवाद को फेंक दिए जाने के बाद विध्वंसक स्वचालित रूप से स्टैक अनइंडिंग के दौरान प्राप्त होगा।

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

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


यह C ++ 03 में तीन का नियम था और C ++ 11 में अब चार का नियम है।
डेडएमजी

1
आप इसे कॉपी कंस्ट्रक्टर, मूव कंस्ट्रक्टर, कॉपी असाइनमेंट, मूव असाइनमेंट और डिस्ट्रक्टर के लिए "रूल ऑफ़ 5" कह सकते हैं। लेकिन कदम अर्थतंत्र हमेशा उचित संसाधन प्रबंधन के लिए आवश्यक नहीं हैं।
चार्ल्स साल्विया

आपको अलग-अलग मूव और कॉपी असाइनमेंट की आवश्यकता नहीं है। कॉपी-एंड-स्वैप मुहावरा दोनों ऑपरेटर एक में कर सकते हैं।
डेडएमजी

2
यह सवाल का जवाब देता है Does C# avoid pitfalls that are avoided in C++ only by careful programming?। इसका जवाब "वास्तव में नहीं है, क्योंकि यह बुरी तरह से आसान है क्योंकि जोएल आधुनिक सी ++ के बारे में बात कर रहा था"
चार्ल्स साल्विया

1
IMO, जबकि उच्च स्तर की भाषाएं जैसे C # या Java आपको स्मृति प्रबंधन और अन्य सामान प्रदान करते हैं जो आपकी सहायता करने वाले हैं , यह हमेशा की तरह नहीं करता है। आप अभी भी अपने कोड डिज़ाइन की तलाश कर रहे हैं ताकि आप कोई मेमोरी लीक न छोड़ें (जो कि आप C ++ में कॉल नहीं करेंगे)। अपने अनुभव से, मुझे C ++ में मेमोरी को प्रबंधित करना आसान ईवीएन लगता है क्योंकि आप जानते हैं कि विध्वंसक कहलाएंगे और ज्यादातर मामलों में वे सफाई करते हैं। आखिरकार, C ++ में ऐसे मामलों के लिए स्मार्ट पॉइंटर्स हैं जब डिजाइन कुशल मेमोरी प्रबंधन के लिए अनुमति नहीं देता है। सी ++ महान है लेकिन डमी के लिए नहीं।
पीजूस

3

मैं वास्तव में सहमत नहीं होगा। शायद सी ++ की तुलना में कम नुकसान हो सकता है क्योंकि यह 1985 में अस्तित्व में था।

क्या C # उन सावधानियों से बचता है जिन्हें C ++ में केवल सावधानीपूर्वक प्रोग्रामिंग से बचा जाता है? यदि हां, तो उन्हें किस डिग्री और कैसे टाला जाता है?

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

  1. C ++ की तरह कोड न करें। यह वास्तव में सिर्फ सामान्य ज्ञान है।
  2. अपने इंटरफेस को प्रतिबंधित करें और इनकैप्सुलेशन का उपयोग करें। OOP।
  3. दो-चरण आरंभीकरण कोड लेखकों को दांव पर जला दिया जाना चाहिए। OOP।
  4. जानिए शब्दार्थ क्या हैं। क्या यह वास्तव में C ++ विशिष्ट है?
  5. अपने इंटरफेस को फिर से प्रतिबंधित करें, इस बार थोड़ा अलग तरीके से। OOP।
  6. आभासी विध्वंसक। हाँ। यह शायद अभी भी मान्य है- कुछ हद तक। finalऔर overrideबेहतर के लिए इस विशेष खेल को बदलने में मदद की है। अपने विध्वंसक बनाने के लिए overrideऔर आप एक अच्छा संकलक त्रुटि की गारंटी देते हैं यदि आप किसी ऐसे व्यक्ति से प्राप्त करते हैं जो अपना विध्वंसक नहीं बना था virtual। अपनी कक्षा बनाएं finalऔर कोई भी खराब स्क्रब साथ न आए और बिना किसी वर्चुअल डिस्ट्रक्टर के इसे गलती से प्राप्त कर सकते हैं।
  7. यदि सफाई कार्य विफल हो जाते हैं तो बुरी चीजें होती हैं। यह वास्तव में सी ++ के लिए विशिष्ट नहीं है - आप जावा और सी # दोनों के लिए एक ही सलाह देख सकते हैं - और, अच्छी तरह से, बहुत अधिक हर भाषा। क्लीनअप फ़ंक्शंस होने में जो विफल हो सकता है वह सिर्फ सादा खराब है और इस आइटम के बारे में C ++ या OOP कुछ भी नहीं है।
  8. इस बात से अवगत रहें कि कंस्ट्रक्टर ऑर्डर आभासी कार्यों को कैसे प्रभावित करता है। उल्लासपूर्वक, जावा में (या तो वर्तमान या अतीत) यह केवल गलत तरीके से व्युत्पन्न वर्ग के फ़ंक्शन को कॉल करेगा, जो कि C ++ के व्यवहार से भी बदतर है। बावजूद, यह समस्या C ++ के लिए विशिष्ट नहीं है।
  9. ऑपरेटर ओवरलोड को लोगों की अपेक्षा के अनुसार व्यवहार करना चाहिए। वास्तव में विशिष्ट नहीं है। नर्क, यह शायद ही विशेष रूप से अतिभारित करने वाला ऑपरेटर है, इसे किसी भी फ़ंक्शन पर लागू किया जा सकता है- इसे एक नाम न दें और फिर इसे पूरी तरह से अनइंस्टिट्यूट करें।
  10. यह वास्तव में अब बुरा अभ्यास माना जाता है। सभी जोरदार-अपवाद-सुरक्षित असाइनमेंट ऑपरेटर स्व-असाइनमेंट के साथ ठीक काम करते हैं, और स्व-असाइनमेंट प्रभावी रूप से एक तार्किक प्रोग्राम त्रुटि है, और स्व-असाइनमेंट के लिए जाँच केवल प्रदर्शन लागत के लायक नहीं है।

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

संपादित करें: C ++ के नुकसान में चीजों के नुकसान शामिल नहीं हैं malloc। मेरा मतलब है, एक के लिए, हर एक ख़तरा जिसे आप सी कोड में पा सकते हैं, आप समान रूप से असुरक्षित सी # कोड में पा सकते हैं, इसलिए यह विशेष रूप से प्रासंगिक नहीं है, और दूसरी बात, सिर्फ इसलिए कि मानक इसे अंतर्संबंध के लिए परिभाषित करता है, इसका मतलब यह नहीं है कि इसका उपयोग करने के लिए इसे + ++ माना जाता है। कोड। मानक भी परिभाषित करता है goto, लेकिन अगर आप स्पेगेटी मेस के विशाल ढेर को इसका उपयोग करने के लिए लिखते हैं, तो मैं समझता हूं कि आपकी समस्या, भाषा की नहीं। "सावधान कोडिंग" और "भाषा के मूल मुहावरों" के बीच एक बड़ा अंतर है।

क्या C # में नए, अलग-अलग नुकसान हो सकते हैं, जो एक नए C # प्रोग्रामर को पता होना चाहिए? यदि हां, तो C # के डिजाइन से वे क्यों नहीं बच सकते?

usingबेकार है। यह वास्तव में करता है। और मुझे नहीं पता कि कुछ बेहतर क्यों नहीं किया गया। इसके अलावा, Base[] = Derived[]और बहुत अधिक हर वस्तु का उपयोग, जो मौजूद है क्योंकि मूल डिजाइनर बड़े पैमाने पर सफलता को नोटिस करने में विफल रहे हैं जो टेम्पलेट सी ++ में थे, और फैसला किया कि "चलो बस सब कुछ सब कुछ से विरासत में मिला और अपनी सभी प्रकार की सुरक्षा खो दें" सबसे अच्छा विकल्प था । मेरा यह भी मानना ​​है कि आप प्रतिनिधियों के साथ दौड़ की स्थिति और इस तरह के अन्य मज़ेदार चीजों में कुछ आश्चर्यचकित कर सकते हैं। फिर अन्य सामान्य चीजें हैं, जैसे कि कैसे जेमिक्स टेम्प्लेट की तुलना में भयानक रूप से चूसते हैं, वास्तव में अनावश्यक सब कुछ एक classऔर इस तरह की चीजों को लागू करते हैं।


5
एक शिक्षित यूजरबेस या नए निर्माण वास्तव में रस्सी को कम नहीं कर रहे हैं। वे बस काम कर रहे हैं-इतने कम लोग खत्म हो गए हैं। हालांकि यह प्रभावी C ++ पर सभी अच्छी टिप्पणी है और भाषा के विकास में इसका संदर्भ है।
तेलस्टिन

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

2
C ++ के C भागों का उपयोग करना unsafeC # में आपके सभी कोड को लिखने के लिए अलग नहीं है, जो कि उतना ही बुरा है। यदि आप चाहें, तो मैं सी # की तरह कोडिंग के हर नुकसान को सूचीबद्ध कर सकता हूं।
डेडएमजी

@DeadMG: तो वास्तव में सवाल यह होना चाहिए "एक C ++ प्रोग्रामर के पास खुद को लटकाने के लिए पर्याप्त रस्सी है जब तक वह एक C प्रोग्रामर है"
gbjbaanb

"प्लस, सी ++ आबादी का अनुपात जो अभी भी पर्याप्त रूप से बेवकूफ, बिना सूचना के हैं, या मैन्युअल मेमोरी प्रबंधन जैसी चीजें करने के लिए दोनों पहले की तुलना में बहुत कम हैं।" प्रशस्ति पत्र की जरूरत।
dan04

3

क्या C # उन सावधानियों से बचता है जिन्हें C ++ में केवल सावधानीपूर्वक प्रोग्रामिंग से बचा जाता है? यदि हां, तो उन्हें किस डिग्री और कैसे टाला जाता है?

C # के फायदे हैं:

  • C के साथ पीछे की ओर संगत नहीं है, इस प्रकार "दुष्ट" भाषा सुविधाओं (जैसे, कच्चे संकेत) की एक लंबी सूची से बचने से बचते हैं जो कि वाक्यविन्यास सुविधाजनक हैं लेकिन अब खराब शैली माना जाता है।
  • मान शब्दार्थ के बजाय संदर्भ शब्दार्थ होने से, जो प्रभावी C ++ आइटम मूट के कम से कम 10 बनाता है (लेकिन नए विवरणों का परिचय देता है)।
  • C ++ से कम कार्यान्वयन-परिभाषित व्यवहार होना।
    • विशेष रूप से, C ++ में , आदि का चरित्र एन्कोडिंग char, stringकार्यान्वयन-परिभाषित है। यूनिकोड के लिए विंडोज दृष्टिकोण ( अप्रचलित "कोड पृष्ठों" के wchar_tलिए यूटीएफ-के charलिए) और * निक्स दृष्टिकोण (यूटीएफ -8) के बीच की छात्रवृत्ति क्रॉस-प्लेटफॉर्म कोड में बड़ी कठिनाइयों का कारण बनती है। C #, OTOH, गारंटी देता है कि एक stringUTF-16 है।

क्या C # में नए, अलग-अलग नुकसान हो सकते हैं, जो एक नए C # प्रोग्रामर को पता होना चाहिए?

हाँ: IDisposable

क्या C # के लिए "प्रभावी C ++" के बराबर पुस्तक है?

प्रभावी C # नामक एक पुस्तक है जो प्रभावी C ++ की संरचना में समान है ।


0

नहीं, C # (और Java) C ++ से कम सुरक्षित हैं

C ++ स्थानीय रूप से सत्यापित है । मैं सी ++ में एक एकल वर्ग का निरीक्षण कर सकता हूं और यह निर्धारित कर सकता हूं कि कक्षा स्मृति या अन्य संसाधनों को लीक नहीं करती है, यह मानते हुए कि सभी संदर्भित कक्षाएं सही हैं। जावा या सी # में, यह निर्धारित करने के लिए प्रत्येक संदर्भित वर्ग की जांच करना आवश्यक है कि क्या उसे किसी प्रकार के अंतिम रूप देने की आवश्यकता है।

सी ++:

{
   some_resource r(...);  // resource initialized
   ...
}  // resource destructor called, no leaks here

सी#:

{
   SomeResource r = new SomeResource(...); // resource initialized
   ...
} // did I need to finalize that?  May I should have used 'using' 
  // (or in Java, a grotesque try/finally construct)?  No way to tell
  // without checking the documentation for SomeResource

सी ++:

{
    auto_ptr<SomeInterface> i = SomeFactory.create(...);
    i->f(...);
} // automatic finalization and memory release.  A new implementation of
  // SomeInterface can allocate and free resources with no impact
  // on existing code

सी#:

{
   SomeInterface i = SomeFactory.create(...);
   i.f(...);
   ...
} // Sure hope someone didn't create an implementation of SomeInterface
  // that requires finalization.  In C# and Java it is necessary to decide whether
  // any implementation could require finalization when the interface is defined.
  // If the initial decision is 'no finalization', then no future implementation  
  // can acquire any resource without creating potential leaks in existing code.

3
... यह आधुनिक IDEs में बहुत मामूली है यह निर्धारित करने के लिए कि क्या कुछ IDisposable से विरासत में मिला है। मुख्य समस्या यह है कि आपको (या उसके कुछ परिजनों को) उपयोग करने के लिए जानना आवश्यक है auto_ptr। वह कहावत है रस्सी।
तेलस्टिन

2
@Telastyn नहीं, मुद्दा यह है कि आप हमेशा एक स्मार्ट पॉइंटर का उपयोग करते हैं, जब तक कि आप वास्तव में नहीं जानते कि आपको एक की आवश्यकता नहीं है। C # में स्टेटमेंट का उपयोग उस रस्सी की तरह है जिस पर आप बात कर रहे हैं। (यानी C ++ में आपको एक स्मार्ट पॉइंटर का उपयोग करना याद रखना होगा, फिर भी C # उतना बुरा क्यों नहीं है, भले ही आपको हमेशा एक स्टेटमेंट का उपयोग करना याद रखना है)
gbjbaanb

1
@gbjananb क्योंकि क्या? C # वर्गों में से 5% डिस्पोजेबल हैं? और आप जानते हैं कि अगर वे डिस्पोजेबल हैं तो आपको उन्हें निपटाने की जरूरत है। C ++ में, हर एक ऑब्जेक्ट डिस्पोजेबल है। और आप नहीं जानते कि क्या आपके विशेष उदाहरण के साथ निपटा जाना चाहिए। पॉइंटर्स के लिए क्या होता है जो एक कारखाने से वापस नहीं किया जाता है? क्या उन्हें साफ करना आपकी जिम्मेदारी है? यह नहीं होना चाहिए, लेकिन कभी-कभी यह होता है। और फिर, सिर्फ इसलिए कि आपको हमेशा एक स्मार्ट पॉइंटर का उपयोग करना चाहिए इसका मतलब यह नहीं है कि विकल्प मौजूद नहीं है। विशेष रूप से शुरुआती लोगों के लिए, यह एक महत्वपूर्ण नुकसान है।
तेलस्टिन

2
@ टेलस्टाइन: उपयोग करने के लिए जानना उतना auto_ptrही सरल है जितना कि उपयोग करना IEnumerableया इंटरफेस का उपयोग करना जानना, या मुद्रा या ऐसे के लिए फ्लोटिंग-पॉइंट का उपयोग न करना। यह DRY का एक बुनियादी अनुप्रयोग है। कोई नहीं जानता कि कार्यक्रम की मूल बातें कैसे वह गलती करेगा। के विपरीत है using। इसके साथ समस्या usingयह है कि आपको हर वर्ग के लिए जानना होगा कि क्या यह डिस्पोजेबल है या नहीं (और मुझे उम्मीद है कि कभी नहीं, कभी बदलता है), और यदि यह डिस्पोजेबल नहीं है, तो आप स्वचालित रूप से सभी व्युत्पन्न वर्गों पर प्रतिबंध लगा सकते हैं जो डिस्पोजेबल हो सकते हैं।
डेडएमजी

2
केविन: उह, आपके जवाब का कोई मतलब नहीं है। यह C # का दोष नहीं है कि आप इसे गलत कर रहे हैं। आप करते नहीं ठीक से लिखा सी # कोड में finalizers पर निर्भर करते हैं । यदि आपके पास एक फ़ील्ड है जिसमें एक Disposeविधि है, तो आपको लागू करना होगा IDisposable('उचित' तरीका)। यदि आपकी कक्षा ऐसा करती है (जो C ++ में आपकी कक्षा के लिए RAII लागू करने के बराबर है), और आप उपयोग करते हैं using(जो C ++ में स्मार्ट पॉइंटर्स की तरह है), तो यह सब पूरी तरह से काम करता है। फाइनल करने वाला ज्यादातर दुर्घटनाओं को रोकने के लिए होता है - Disposeशुद्धता के लिए जिम्मेदार है, और यदि आप इसका उपयोग नहीं कर रहे हैं, तो ठीक है, यह आपकी गलती है, न कि सी #।
user541686

0

हाँ 100% हाँ, जैसा कि मुझे लगता है कि इसकी मुफ्त मेमोरी को असंभव है और इसे C # में उपयोग किया जाता है (इसके प्रबंधन को संभालने और आप असुरक्षित मोड में नहीं जाते हैं)।

लेकिन अगर आप जानते हैं कि C ++ में कैसे प्रोग्राम करना है, जो अविश्वसनीय संख्या में लोग नहीं करते हैं। तुम बहुत ठीक हो। जैसे चार्ल्स साल्विया वर्ग वास्तव में अपनी यादों को प्रबंधित नहीं करते हैं क्योंकि यह सभी पूर्ववर्ती एसटीएल कक्षाओं में नियंत्रित किया जाता है। मैं शायद ही कभी संकेत का उपयोग करता हूं। वास्तव में मैं एक भी सूचक का उपयोग किए बिना परियोजनाओं चला गया। (C ++ 11 यह आसान बनाता है)।

जैसा कि टाइपो, मूर्खतापूर्ण गलतियों और आदि बनाने के लिए (उदाहरण के लिए: if (i=0)बीसी कुंजी तब अटक जाती है जब आप हिट == वास्तव में जल्दी से) कंपाइलर शिकायत करता है जो अच्छा है क्योंकि यह कोड की गुणवत्ता में सुधार करता है। अन्य उदाहरण breakस्विच स्टेटमेंट में भूल रहे हैं और आपको किसी फ़ंक्शन में स्थिर चर घोषित करने की अनुमति नहीं दे रहे हैं (जो मुझे कभी-कभी नापसंद है लेकिन एक अच्छा विचार है)।


4
जावा और C # ने संदर्भ समानता का उपयोग करके और मूल्य समानता के लिए शुरू करके =/ ==समस्या को और भी बदतर बना दिया । गरीब प्रोग्रामर को अब इस बात का ध्यान रखना होगा कि क्या एक चर 'डबल' या 'डबल' है और सही वेरिएंट को कॉल करना सुनिश्चित करें। ==.equals
केविन क्लाइन

@kevincline +1 लेकिन C # में structआप वह ==काम कर सकते हैं जो उस समय के बहुमत से अविश्वसनीय रूप से अच्छी तरह से काम करता है, जिसमें केवल स्ट्रिंग्स, इनट्स और फ्लोट्स (यानी केवल संरचनात्मक सदस्य) होंगे। अपने स्वयं के कोड में मुझे वह समस्या कभी नहीं मिलती है, जब मैं सरणियों की तुलना करना चाहता हूं। मुझे नहीं लगता कि मैं कभी सूची या गैर-संरचना प्रकार (स्ट्रिंग, इंट, फ्लोट,

2
==मूल्य समानता और isसंदर्भ समानता के लिए उपयोग करके पायथन ने इसे सही पाया ।
dan04

@ dan04 - आपको लगता है कि C # में कितने प्रकार की समानता है? उत्कृष्ट ACCU बिजली की बात देखें: कुछ वस्तुएं दूसरों की तुलना में अधिक समान हैं
मार्क बूथ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.