क्या जावा के डेवलपर्स ने जानबूझकर RAII को त्याग दिया था?


82

एक लंबे समय के C # प्रोग्रामर के रूप में, मैं हाल ही में संसाधन अधिग्रहण इनिशियलाइजेशन (RAII) के लाभों के बारे में अधिक जानने के लिए आया हूं । विशेष रूप से, मुझे पता चला है कि C # मुहावरा:

using (var dbConn = new DbConnection(connStr)) {
    // do stuff with dbConn
}

C ++ समतुल्य है:

{
    DbConnection dbConn(connStr);
    // do stuff with dbConn
}

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

class Foo {
    DbConnection dbConn;

    // ...
}

C # में मुझे Foo IDisposableको इस तरह लागू करना होगा :

class Foo : IDisposable {
    DbConnection dbConn;

    public void Dispose()
    {       
        dbConn.Dispose();
    }
}

और क्या बुरा है, प्रत्येक उपयोगकर्ता को एक ब्लॉक में Fooसंलग्न करने के लिए याद रखने की आवश्यकता होगी , जैसे:Foousing

   using (var foo = new Foo()) {
       // do stuff with "foo"
   }

अब C # और इसके जावा रूट्स को देखकर मुझे आश्चर्य हो रहा है ... क्या जावा के डेवलपर्स ने पूरी तरह से सराहना की कि वे क्या दे रहे थे जब उन्होंने ढेर के पक्ष में ढेर छोड़ दिया, इस प्रकार RAII को छोड़ दिया?

(इसी तरह, स्ट्रॉस्ट्रुप ने पूरी तरह से RAII के महत्व की सराहना की?)


5
मुझे यकीन नहीं है कि आप सी ++ में संसाधनों को संलग्न नहीं करने के बारे में क्या बात कर रहे हैं। DBConnection ऑब्जेक्ट संभवतः अपने विध्वंसक में सभी संसाधनों को बंद कर देता है।
मेपल_शाफ्ट

16
@maple_shaft, बिल्कुल मेरी बात! यह C ++ का लाभ है जो मैं इस प्रश्न में संबोधित कर रहा हूं। C # में आपको "++" ... C ++ में संसाधनों का संलग्न करने की आवश्यकता नहीं है।
जोएलफैन

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

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

8
@JimInTexas: मुझे लगता है कि सीन में कहीं न कहीं सच्चाई का एक मूल बीज है (हालाँकि टेम्पलेट नहीं है लेकिन अपवाद क्रूरता है)। कंस्ट्रक्टर / डिस्ट्रक्टर्स शुरू से ही वहाँ थे, लेकिन वहाँ महत्व और आरएआई की अवधारणा शुरू में नहीं थी (मुझे जिस शब्द की तलाश है) का एहसास हुआ। कंपाइलर्स को अच्छा होने में कुछ साल और कुछ समय लगा, इससे पहले कि हमें एहसास हो जाए कि पूरा RAII कितना महत्वपूर्ण है।
मार्टिन यॉर्क

जवाबों:


38

अब C # और इसके जावा रूट्स को देखकर मुझे आश्चर्य हो रहा है ... क्या जावा के डेवलपर्स ने पूरी तरह से सराहना की कि वे क्या दे रहे थे जब उन्होंने ढेर के पक्ष में ढेर छोड़ दिया, इस प्रकार RAII को छोड़ दिया?

(इसी तरह, स्ट्रॉस्ट्रुप ने पूरी तरह से RAII के महत्व की सराहना की?)

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

मज़ेदार रूप से, यहां तक ​​कि स्ट्रॉस्ट्रुप को उस समय के नियतात्मक विनाशकों के महत्व के बारे में पता नहीं था, जब उन्होंने उन्हें डिजाइन किया था। मैं बोली नहीं ढूँढ सकता, लेकिन अगर आप वास्तव में हैं, तो आप इसे उनके साक्षात्कारों के बीच यहाँ पा सकते हैं: http : //www.stroustrupupinterview.html


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

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

26
@delan। मैं C ++ स्मार्ट पॉइंटर्स manualमेमोरी मैनेजमेंट नहीं कहूंगा । वे नियतात्मक ठीक अनाज नियंत्रणीय कचरा कलेक्टर की तरह अधिक हैं। अगर सही तरीके से इस्तेमाल किया जाए तो स्मार्ट पॉइंट्स मधुमक्खियों के घुटने होते हैं।
मार्टिन न्यूयार्क

10
@ लोकीअस्तारी: ठीक है, मैं कहूंगा कि वे पूर्ण जीसी से थोड़ा कम स्वचालित हैं (आपको यह सोचना होगा कि आप वास्तव में किस तरह की स्मार्टनेस चाहते हैं) और उन्हें पुस्तकालय के रूप में लागू करने के लिए कच्चे पॉइंटर्स (और इसलिए मैनुअल मेमोरी मैनेजमेंट) का निर्माण करना होगा। । इसके अलावा, मैं चक्रीय संदर्भों को स्वचालित रूप से हैंडल करने की तुलना में किसी भी स्मार्ट पॉइंटर के बारे में नहीं जानता, जो कि मेरी पुस्तकों में कचरा संग्रह की सख्त आवश्यकता है। स्मार्ट पॉइंटर्स निश्चित रूप से अविश्वसनीय रूप से शांत और उपयोगी हैं, लेकिन आपको पूरी तरह से और विशेष रूप से GC'd भाषा में कुछ गारंटी प्रदान करना होगा (चाहे आप उन्हें उपयोगी समझें या नहीं)।

11
@delan: मुझे वहाँ असहमत होना है। मुझे लगता है कि वे जीसी से अधिक स्वचालित हैं क्योंकि वे नियतात्मक हैं। ठीक। कुशल होने के लिए आपको यह सुनिश्चित करने की आवश्यकता है कि आप सही का उपयोग करें (मैं आपको दे दूंगा)। std :: weak_ptr साइकिल को पूरी तरह से अच्छी तरह से संभालता है। चक्रों को हमेशा बाहर रखा जाता है लेकिन वास्तव में यह वास्तव में शायद ही कभी एक समस्या है क्योंकि आधार वस्तु आमतौर पर स्टैक आधारित होती है और जब यह जाती है तो यह बाकी को साफ कर देगी। दुर्लभ मामलों के लिए यह एक समस्या std :: weak_ptr हो सकती है।
मार्टिन यॉर्क

60

हां, C # (और, मुझे यकीन है, जावा) के डिजाइनरों ने विशेष रूप से निर्धारक अंतिमकरण के खिलाफ फैसला किया है। मैंने 1999-2002 के इस कई बार के बारे में एंडर्स हेजलबर्ग से पूछा।

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

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

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

C # में, आपके पास usingकीवर्ड है, जो C # 1.0 के डिजाइन में काफी देरी से आया है। पूरी IDisposableबात बहुत ही मनहूस है, और एक आश्चर्य की बात है कि अगर उन कक्षाओं को चिह्नित usingकरने के लिए सी ++ डिस्ट्रक्टर सिंटैक्स के साथ काम करना अधिक सुरुचिपूर्ण होगा, तो ~बॉयलर-प्लेट IDisposableपैटर्न को स्वचालित रूप से लागू किया जा सकता है?


2
सी ++ / सीएलआई (.NET) ने क्या किया है, जहां प्रबंधित हीप की वस्तुओं में स्टैक-आधारित "हैंडल" भी होता है, जो आरआईएए प्रदान करता है?
जोएलफैन

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

5
+1 यह अब तक का एकमात्र सही उत्तर है - ऐसा इसलिए है क्योंकि जावा जानबूझकर (गैर-आदिम) स्टैक-आधारित ऑब्जेक्ट नहीं है।
ब्लूराजा - डैनी पफ्लुगुएफ्ट '

8
@ अभिनेता टेलर - सही है। लेकिन मुझे लगता है कि सी # गैर-नियतात्मक विध्वंसक बहुत कम मूल्य का है, क्योंकि आप किसी भी तरह के विवश संसाधन का प्रबंधन करने के लिए उस पर भरोसा नहीं कर सकते हैं। इसलिए, मेरी राय में, ~सिंटेक्स का उपयोग करना बेहतर हो सकता है, के लिए वाक्यविन्यास चीनी होना चाहिएIDisposable.Dispose()
लैरी ओब्रायन

3
@ लॉरी: मैं सहमत हूं। C ++ / CLI है का उपयोग ~करने के लिए वाक्यात्मक चीनी के रूप में IDisposable.Dispose()है, और यह बहुत सी # सिंटेक्स की तुलना में अधिक सुविधाजनक है।
dan04

41

ध्यान रखें कि जावा का विकास 1991-1995 में हुआ था जब C ++ बहुत अलग भाषा थी। अपवाद (जिसने RAII को आवश्यक बना दिया था ) और टेम्पलेट्स (जिसने स्मार्ट पॉइंटर्स को लागू करना आसान बना दिया) "नई-नई" विशेषताएं थीं। अधिकांश सी ++ प्रोग्रामर सी से आए थे और मैनुअल मेमोरी मैनेजमेंट करने के लिए उपयोग किए गए थे।

इसलिए मुझे संदेह है कि जावा के डेवलपर्स ने जानबूझकर RAII को छोड़ने का फैसला किया है। हालांकि, यह जावा के लिए एक सुविचारित निर्णय था कि मूल्य शब्दार्थ के बजाय संदर्भ शब्दार्थ को प्राथमिकता दी जाए। नियतात्मक विनाश एक संदर्भ-शब्दार्थ भाषा में लागू करना मुश्किल है।

तो मूल्य शब्दार्थ के बजाय संदर्भ शब्दार्थ का उपयोग क्यों करें?

क्योंकि यह भाषा को बहुत सरल बनाता है।

  • के बीच एक वाक्यात्मक गौरव के लिए कोई जरूरत नहीं है Fooऔर Foo*या के बीच foo.barऔर foo->bar
  • अतिभारित असाइनमेंट की कोई आवश्यकता नहीं है, जब सभी असाइनमेंट पॉइंटर को कॉपी करता है।
  • कॉपी कंस्ट्रक्टर की कोई जरूरत नहीं है। ( कभी-कभी एक स्पष्ट प्रतिलिपि फ़ंक्शन की clone()आवश्यकता होती है, जैसे कि।
  • privateकॉपी कंस्ट्रक्टर घोषित operator=करने और एक वर्ग को गैर-योग्य बनाने की कोई आवश्यकता नहीं है । यदि आप किसी वर्ग की वस्तुओं को कॉपी नहीं करना चाहते हैं, तो आप इसे कॉपी करने के लिए फ़ंक्शन नहीं लिखते हैं।
  • swapकार्यों के लिए कोई आवश्यकता नहीं है । (जब तक आप एक नियमित दिनचर्या नहीं लिख रहे हैं।)
  • C ++ 0x-style rvalue संदर्भों की कोई आवश्यकता नहीं है।
  • (N) RVO की कोई आवश्यकता नहीं है।
  • कोई स्लाइसिंग समस्या नहीं है।
  • कंपाइलर के लिए ऑब्जेक्ट लेआउट निर्धारित करना आसान है, क्योंकि संदर्भों का एक निश्चित आकार है।

संदर्भ शब्दार्थों के लिए मुख्य नकारात्मक पक्ष यह है कि जब प्रत्येक वस्तु में संभावित रूप से कई संदर्भ होते हैं, तो यह जानना कठिन हो जाता है कि इसे कब हटाएं। आप काफी है स्वचालित स्मृति प्रबंधन के लिए।

जावा ने एक गैर-नियतात्मक कचरा कलेक्टर का उपयोग करने के लिए चुना।

क्या जीसी निर्धारक नहीं हो सकता है?

हाँ यह कर सकते हैं। उदाहरण के लिए, पायथन का सी कार्यान्वयन संदर्भ गिनती का उपयोग करता है। और बाद में चक्रीय कचरे को संभालने के लिए GC को ट्रेसिंग में जोड़ा गया, जहाँ पर रिफ्लक्स विफल हो जाते हैं।

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

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

लेकिन सी ++ / सीएलआई "स्टैक ऑब्जेक्ट्स" के बारे में क्या?

वे ( मूल लिंक ) के लिए सिंटैक्टिक शुगर हैंDispose , बहुत सी # की तरह । हालाँकि, यह नियतात्मक विनाश की सामान्य समस्या को हल नहीं करता है, क्योंकि आप एक अनाम बना सकते हैं और C ++ / CLI इसे ऑटो-डिस्पोज़ नहीं करेंगे।usinggcnew FileStream("filename.ext")


3
इसके अलावा, अच्छे लिंक (विशेष रूप से पहले वाले, जो इस चर्चा के लिए अत्यधिक प्रासंगिक हैं)
ब्लूराजा - डैनी पफ्लुगुएफ्ट

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

1
"कॉपी कंस्ट्रक्टर्स की कोई आवश्यकता नहीं" अच्छा लगता है, लेकिन व्यवहार में बुरी तरह से विफल हो जाता है। java.util.Date और कैलेंडर शायद सबसे कुख्यात उदाहरण हैं। से अधिक कुछ नहीं new Date(oldDate.getTime())
केविन क्लाइन

2
Iow RAII को "छोड़ दिया" नहीं गया था, यह बस छोड़ दिया जाने के लिए मौजूद नहीं था :) निर्माणकर्ताओं की नकल करने के लिए, मैंने कभी भी उन्हें पसंद नहीं किया है, गलत होने के लिए बहुत आसान है, वे सिरदर्द का एक निरंतर स्रोत हैं जब कहीं गहरे नीचे किसी को (और) एक गहरी प्रतिलिपि बनाना भूल गया, जिससे संसाधनों को उन प्रतियों के बीच साझा किया जाना चाहिए जो नहीं होनी चाहिए।
jwenting

20

Java7 ने C # using: The-try-with-Resources कथन के समान कुछ पेश किया

एक tryबयान जो एक या अधिक संसाधनों की घोषणा करता है। एक संसाधन एक वस्तु के रूप में है जिसे कार्यक्रम के साथ समाप्त होने के बाद बंद किया जाना चाहिए। try-साथ-संसाधनों बयान सुनिश्चित करता है कि प्रत्येक संसाधन बयान के अंत में बंद कर दिया है। कोई भी वस्तु जो लागू होती है java.lang.AutoCloseable, जिसमें सभी ऑब्जेक्ट शामिल हैं जो लागू होते हैं java.io.Closeable, एक संसाधन के रूप में उपयोग किया जा सकता है ...

इसलिए मुझे लगता है कि उन्होंने या तो सचेत रूप से RAII को लागू नहीं करने का चयन किया या उन्होंने इस बीच अपना मन बदल दिया।


दिलचस्प है, लेकिन ऐसा लगता है कि यह केवल उन वस्तुओं के साथ काम करता है जो कार्यान्वित करते हैं java.lang.AutoCloseable। शायद कोई बड़ी बात नहीं है, लेकिन मुझे यह पसंद नहीं है कि यह कैसा महसूस होता है। शायद मेरे पास कुछ अन्य वस्तु है जो स्वचालित रूप से निर्भर होनी चाहिए, लेकिन इसे लागू करने के लिए यह शब्द बहुत ही अजीब है AutoCloseable...
FrustratedWithFormsDesigner 19

9
@ पैट्रिक: एर, तो? usingRAII जैसा नहीं है - एक मामले में कॉलर संसाधनों के निपटान के बारे में चिंता करता है, दूसरे मामले में कैली इसे संभालती है।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

1
+1 मैं संसाधनों के साथ प्रयास के बारे में नहीं जानता था; यह अधिक बॉयलरप्लेट को डंप करने में उपयोगी होना चाहिए।
jprete

3
-1 के लिए using/ कोशिश के साथ संसाधनों RAII के रूप में ही नहीं किया जा रहा है।
सीन मैकमिलन

4
@ सीन: सहमत। usingऔर यह ilk RAII के पास कहीं नहीं है।
डेडएमजी नोव

18

जावा जानबूझकर स्टैक-आधारित ऑब्जेक्ट्स (उर्फ मूल्य-ऑब्जेक्ट्स) नहीं है। इस तरह की विधि के अंत में वस्तु को स्वचालित रूप से नष्ट होने के लिए ये आवश्यक हैं।

इसके कारण और यह तथ्य कि जावा कचरा-एकत्रित है, निर्धारक अंतिमकरण अधिक-या-कम असंभव है (पूर्व। यदि मेरी "स्थानीय" वस्तु कहीं और संदर्भित हो जाती है? तो जब विधि समाप्त हो जाती है, तो हम इसे नष्ट नहीं करना चाहते हैं? ) का है

हालाँकि, यह हम में से अधिकांश के साथ ठीक है, क्योंकि मूल (सी ++) संसाधनों के साथ बातचीत करते हुए, लगभग अंतिम निर्धारण की आवश्यकता कभी नहीं होती है !


जावा में स्टैक-आधारित ऑब्जेक्ट क्यों नहीं हैं?

(आदिम से इतर ..)

क्योंकि ढेर-आधारित वस्तुओं में ढेर-आधारित संदर्भों की तुलना में अलग-अलग शब्दार्थ होते हैं। C ++ में निम्नलिखित कोड की कल्पना करें; यह क्या करता है?

return myObject;
  • यदि myObjectएक स्थानीय स्टैक-आधारित ऑब्जेक्ट है, तो कॉपी-कंस्ट्रक्टर को कहा जाता है (यदि परिणाम किसी चीज़ को सौंपा गया है)।
  • यदि myObjectएक स्थानीय स्टैक-आधारित ऑब्जेक्ट है और हम एक संदर्भ लौटा रहे हैं, तो परिणाम अपरिभाषित है।
  • यदि myObjectकोई सदस्य / वैश्विक वस्तु है, तो कॉपी-कंस्ट्रक्टर को कहा जाता है (यदि परिणाम किसी चीज़ को सौंपा गया है)।
  • यदि myObjectकोई सदस्य / वैश्विक ऑब्जेक्ट है और हम एक संदर्भ लौटा रहे हैं, तो संदर्भ वापस आ गया है।
  • यदि myObjectएक स्थानीय स्टैक-आधारित ऑब्जेक्ट के लिए एक पॉइंटर है, तो परिणाम अपरिभाषित है।
  • यदि myObjectकोई सदस्य / वैश्विक ऑब्जेक्ट के लिए एक पॉइंटर है, तो वह पॉइंटर लौटा दिया जाता है।
  • यदि myObjectकोई हीप-आधारित ऑब्जेक्ट के लिए एक पॉइंटर है, तो वह पॉइंटर वापस आ जाता है।

अब जावा में समान कोड क्या करता है?

return myObject;
  • संदर्भ दिया गया myObjectहै। इससे कोई फर्क नहीं पड़ता कि चर स्थानीय, सदस्य या वैश्विक है; और चिंता करने के लिए स्टैक-आधारित ऑब्जेक्ट या पॉइंटर मामले नहीं हैं।

उपरोक्त दिखाता है कि स्टैक-आधारित ऑब्जेक्ट C ++ में प्रोग्रामिंग त्रुटियों का एक बहुत ही सामान्य कारण है। उसके कारण, जावा डिजाइनरों ने उन्हें बाहर निकाल दिया; और उनके बिना, जावा में RAII का उपयोग करने का कोई मतलब नहीं है।


6
मुझे नहीं पता कि "RAII का कोई मतलब नहीं है" से आपका क्या मतलब है ... मुझे लगता है कि आपका मतलब है "Java में RAII प्रदान करने की कोई क्षमता नहीं है ... RAII किसी भी भाषा से स्वतंत्र है ... यह नहीं है "व्यर्थ" बनें क्योंकि 1 विशेष भाषा इसे प्रदान नहीं करती है
जोएलफान

4
यह एक वैध कारण नहीं है। स्टैक-आधारित RAII का उपयोग करने के लिए किसी ऑब्जेक्ट को वास्तव में स्टैक पर नहीं रहना पड़ता है। यदि "अनूठे संदर्भ" के रूप में ऐसी कोई चीज है, तो एक बार यह गुंजाइश से बाहर हो जाने पर विध्वंसक को निकाल दिया जा सकता है। उदाहरण के लिए देखें, यह डी प्रोग्रामिंग भाषा के साथ कैसे काम करता है: d-programming-language.org/exception-safe.html
Nemanja Trifunovic

3
@Nemanja: एक वस्तु नहीं है है ढेर पर रहने के ढेर आधारित अर्थ विज्ञान है, और मैं कभी नहीं कहा कि यह किया था। लेकिन यह समस्या नहीं है; समस्या, जैसा कि मैंने उल्लेख किया है, स्टैक-आधारित शब्दार्थ है।
ब्लूराजा -

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

8
@NemanjaTrifunovic: आप लाइव डेटाबेस कनेक्शन पर यूनिट परीक्षण क्यों कर रहे हैं? यह वास्तव में एक इकाई परीक्षण नहीं है। नहीं, क्षमा करें, मैं इसे नहीं खरीद रहा हूं। आपको वैसे भी सभी जगहों पर DB कनेक्शन नहीं बनाने चाहिए, आपको उन्हें कंस्ट्रक्टर या प्रॉपर्टी के माध्यम से पास करना चाहिए, और इसका मतलब है कि आप स्टैक-जैसे ऑटो-डिस्ट्रक्ट सिमेंटिक्स नहीं चाहते हैं। बहुत कम ऑब्जेक्ट जो डेटाबेस कनेक्शन पर निर्भर करते हैं, उन्हें वास्तव में इसका मालिक होना चाहिए। यदि गैर-नियतात्मक सफाई आपको अक्सर काट रही है, तो यह कठिन है, तो यह खराब एप्लिकेशन डिजाइन के कारण है, न कि खराब भाषा डिजाइन के कारण।
Aaronaught

17

के छिद्रों का आपका वर्णन usingअधूरा है। निम्नलिखित समस्या पर विचार करें:

interface Bar {
    ...
}
class Foo : Bar, IDisposable {
    ...
}

Bar b = new Foo();

// Where's the Dispose?

मेरी राय में, RAII और GC दोनों का नहीं होना एक बुरा विचार था। यह जावा में फ़ाइलों को बंद करने की बात आती है, यह malloc()और free()वहाँ पर।


2
मैं मानता हूं कि RAII मधुमक्खियों का घुटना है। लेकिन usingक्लॉज जावा पर C # के लिए एक बेहतरीन कदम है। यह नियतात्मक विनाश की अनुमति देता है और इस प्रकार सही संसाधन प्रबंधन (यह उतना अच्छा नहीं है जितना कि RAII जितना आपको यह करने के लिए याद रखने की आवश्यकता है, लेकिन यह निश्चित रूप से एक अच्छा विचार है)।
मार्टिन यॉर्क

8
"जब जावा में फाइल बंद करने की बात आती है, तो यह मॉलॉक () और वहां पर मुफ्त () है।" - बिल्कुल
कोनराड रुडोल्फ

9
@KonradRudolph: यह मॉलॉक और फ्री से भी बदतर है। कम से कम C में आपके पास अपवाद नहीं हैं।
नेमेनजा ट्रिफ़ुनोविक 18

1
@ नेमजा: चलो, तुम निष्पक्ष हो सकते free()हो finally
डेडएमजी

4
@ लोकी: आधार वर्ग की समस्या एक समस्या के रूप में ज्यादा महत्वपूर्ण है। उदाहरण के लिए, मूल IEnumerableसे विरासत में नहीं मिला था IDisposable, और विशेष पुनरावृत्तियों का एक समूह था, जिसे कभी भी लागू नहीं किया जा सकता था।
डेडएमजी

14

मैं बहुत बूढ़ा हो गया हूं। मैं वहां गया और इसे देखा और कई बार इसके बारे में अपना सिर पीटा।

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

अब उन्होंने भाषा की युक्ति में फाइनल जोड़ा और जावा ने कुछ अपनापन देखा।

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

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

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

तो उन्होंने ऐसा क्यों किया, जब वे शुरू से ही प्रत्येक स्कोप ब्लॉक पर स्वचालित रूप से रखे गए शैली-शब्दार्थ का उपयोग कर सकते थे। शायद दक्षता, लेकिन मुझे लगता है कि वे सिर्फ एहसास नहीं था पसंद है। जैसे अंततः उन्हें एहसास हुआ कि आपको अभी भी .NET (google SafeHandle) में स्मार्ट पॉइंटर्स की आवश्यकता है, उन्होंने सोचा कि GC वास्तव में सभी समस्याओं का समाधान करेगा। वे यह भूल गए कि एक वस्तु केवल स्मृति से अधिक है और जीसी को मुख्य रूप से स्मृति प्रबंधन को संभालने के लिए डिज़ाइन किया गया है। वे इस विचार में फंस गए कि जीसी इसे संभाल लेगा, और यह भूल गया कि आपने अन्य सामान वहां रखा है, एक वस्तु सिर्फ स्मृति की एक बूँद नहीं है जो कि अगर आप इसे थोड़ी देर के लिए नहीं हटाते हैं तो कोई फर्क नहीं पड़ता।

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

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

तो IMHO, जिस तरह से .NET ने बस जावा की सबसे बड़ी खामी को कॉपी किया है, वह इसकी सबसे बड़ी कमजोरी है। .NET एक बेहतर C ++ होना चाहिए था, एक बेहतर जावा नहीं।


IMHO, ब्लॉक 'का उपयोग कर' जैसी चीजें नियतात्मक सफाई के लिए सही दृष्टिकोण हैं, लेकिन कुछ और चीजों की भी आवश्यकता है: (1) यह सुनिश्चित करने का एक साधन कि वस्तुएं निपट जाती हैं यदि उनके विध्वंसक अपवाद फेंकते हैं; (2) एक निर्देश Disposeके साथ चिह्नित सभी क्षेत्रों पर कॉल करने के लिए एक ऑटो-जेनरेटिंग रूटीन विधि का एक साधन using, और निर्दिष्ट IDisposable.Disposeकरना कि क्या इसे स्वचालित रूप से कॉल करना चाहिए; (3) एक निर्देश के समान using, लेकिन जो केवल Disposeएक अपवाद के मामले में कॉल करेगा ; (4) एक भिन्नता IDisposableजिसका एक Exceptionपैरामीटर लगेगा , और ...
सुपरकैट

... जिसका उपयोग usingयदि उचित हो तो स्वचालित रूप से किया जाएगा ; पैरामीटर होगा nullयदि usingब्लॉक सामान्य रूप से बाहर निकलता है, या फिर यह इंगित करेगा कि अपवाद के माध्यम से बाहर निकलने पर क्या अपवाद लंबित था। यदि ऐसी चीजें मौजूद थीं, तो संसाधनों को प्रभावी ढंग से प्रबंधित करना और लीक से बचना बहुत आसान होगा।
सुपरकैट

11

ब्रूस एकेल, "थिंकिंग इन जावा" और "थिंकिंग इन सी ++" के लेखक और सी ++ स्टैण्डर्ड कमेटी के सदस्य, का मत है कि, कई क्षेत्रों में (न सिर्फ RAII), गोस्लिंग और जावा टीम ने अपना काम नहीं किया। घर का पाठ।

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

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

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

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

सूची उस बिंदु पर जाती है जहां यह सिर्फ थकाऊ है ...


5
यह RAII पर ध्यान केंद्रित करने के बजाय जावा बनाम C ++ उत्तर की तरह लगता है। मुझे लगता है कि सी ++ और जावा अलग-अलग भाषाएं हैं, जिनमें से प्रत्येक अपनी ताकत और कमजोरियों के साथ है। इसके अलावा सी ++ डिजाइनरों कई क्षेत्रों में उनके होमवर्क (लागू नहीं किया KISS सिद्धांत, लापता कक्षाओं के लिए सरल आयात तंत्र, आदि) नहीं किया। लेकिन सवाल का ध्यान RAII था: यह जावा में गायब है और आपको इसे मैन्युअल रूप से प्रोग्राम करना होगा।
जियोर्जियो

4
@ जियोर्जियो: लेख की बात है, लगता है कि जावा कई मुद्दों पर नाव से चूक गया है, जिनमें से कुछ सीधे आरएआई से संबंधित हैं। C ++ और जावा पर इसके प्रभाव के बारे में, Eckels नोट करता है: "आपको प्राथमिक डिजाइन के फैसले को ध्यान में रखना चाहिए, जिस पर C ++ में सब कुछ लटका हुआ है: C. के साथ संगतता। यह एक बहुत बड़ी बाधा थी, और हमेशा C ++ की सबसे बड़ी ताकत रही है ... और इसकी बैन। इसने जावा डिजाइनरों को भी बेवकूफ बनाया जो C ++ को अच्छी तरह से नहीं समझते थे। " C ++ के डिज़ाइन ने जावा को सीधे प्रभावित किया, जबकि C # को दोनों से सीखने का अवसर मिला। (चाहे उसने ऐसा किया हो, एक और सवाल है।)
ग्नमेमे

2
@ जियोर्जियो एक विशेष प्रतिमान और भाषा परिवार में मौजूदा भाषाओं का अध्ययन वास्तव में नई भाषा के विकास के लिए आवश्यक होमवर्क का एक हिस्सा है। यह एक उदाहरण है जहां उन्होंने इसे जावा के साथ जोड़ा। उनके पास देखने के लिए C ++ और Smalltalk था। C ++ में यह देखने के लिए जावा नहीं था कि इसे कब विकसित किया गया था।
जेरेमी

1
@Gnawme: "जावा ने कई मुद्दों पर नाव को याद किया है, जिनमें से कुछ सीधे RAII से संबंधित हैं": क्या आप इन मुद्दों का उल्लेख कर सकते हैं? आपके द्वारा पोस्ट किया गया लेख RAII का उल्लेख नहीं करता है।
जियोर्जियो

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

10

सबसे अच्छा कारण यहां के अधिकांश उत्तरों की तुलना में बहुत सरल है।

आप स्टैक आवंटित ऑब्जेक्ट को अन्य थ्रेड्स में पास नहीं कर सकते।

बंद करो और उसके बारे में सोचो। सोचते रहो .... अब C ++ में धागे नहीं थे जब हर कोई RAII में इतना उत्सुक था। यहां तक ​​कि एरलांग (प्रति धागे के लिए अलग ढेर) जब आप बहुत सारी वस्तुओं को पास करते हैं, तो icky हो जाता है। C ++ को C ++ 2011 में केवल एक मेमोरी मॉडल मिला; अब आप अपने कंपाइलर के "डॉक्यूमेंटेशन" का संदर्भ लिए बिना C ++ में कंसीडर के बारे में लगभग कारण बता सकते हैं।

जावा को कई थ्रेड्स के लिए (लगभग) दिन एक से डिज़ाइन किया गया था।

मुझे अभी भी "C ++ प्रोग्रामिंग लैंग्वेज" की मेरी पुरानी कॉपी मिली है, जहां स्ट्रॉस्ट्रुप ने मुझे आश्वासन दिया है कि मुझे थ्रेड्स की आवश्यकता नहीं होगी।

दूसरा दर्दनाक कारण स्लाइसिंग से बचना है।


1
कई थ्रेड्स के लिए डिज़ाइन किया जा रहा जावा यह भी बताता है कि जीसी संदर्भ गणना पर आधारित क्यों नहीं है।
dan04

4
@NemanjaTrifunovic: आप जावा या C # से C ++ / CLI की तुलना नहीं कर सकते, यह लगभग मानव रहित C / C ++ कोड के साथ इंटरप्रोटेट करने के एक्सप्रेस उद्देश्य के लिए डिज़ाइन किया गया था; यह एक अप्रबंधित भाषा की तरह है जो इसके विपरीत .NET फ्रेमवर्क की पहुँच देने के लिए होता है।
Aaronaught

3
@NemanjaTrifunovic: हां, C ++ / CLI इसका एक उदाहरण है कि यह किस तरह से किया जा सकता है जो सामान्य अनुप्रयोगों के लिए पूरी तरह से अनुपयुक्त है । यह केवल C / C ++ इंटरोप के लिए उपयोगी है। न केवल सामान्य डेवलपर्स को पूरी तरह से अप्रासंगिक "स्टैक या हीप" निर्णय से दुखी होने की आवश्यकता नहीं है, लेकिन यदि आप कभी भी इसे फिर से भरने की कोशिश करते हैं तो यह गलती से एक अशक्त सूचक / संदर्भ त्रुटि और / या एक स्मृति रिसाव बनाने के लिए आसान है। क्षमा करें, लेकिन मुझे आश्चर्य होगा कि क्या आपने वास्तव में जावा या सी # में प्रोग्राम किया है, क्योंकि मुझे नहीं लगता कि जो कोई भी वास्तव में सी ++ / सीएलआई में प्रयुक्त शब्दार्थ चाहता है।
हारून

2
@Aaronaught: मैंने जावा (थोड़ा) और C # (बहुत) दोनों के साथ प्रोग्राम किया है और मेरा वर्तमान प्रोजेक्ट सभी # 1 से बहुत अधिक है। मेरा विश्वास करो, मुझे पता है कि मैं किस बारे में बात कर रहा हूं, और इसका "स्टैक बनाम हीप" से कोई लेना-देना नहीं है - यह सुनिश्चित करने के लिए सब कुछ है कि आपके सभी संसाधन जल्द से जल्द जारी किए जाएं, जिनकी आपको आवश्यकता नहीं है। खुद ब खुद। यदि वे नहीं हैं - तो आप मुश्किल में पड़ जाएंगे
नागेज़ा ट्रिफ़ुनोविक

4
@NemanjaTrifunovic: यह बहुत अच्छा है, वास्तव में बहुत अच्छा है, लेकिन C # और C ++ / CLI दोनों के लिए आपको स्पष्ट रूप से यह बताने की आवश्यकता है कि जब आप ऐसा करना चाहते हैं, तो वे बस एक अलग वाक्यविन्यास का उपयोग करते हैं। किसी को भी उस आवश्यक बिंदु पर विवाद नहीं करना चाहिए जिसे आप वर्तमान में चला रहे हैं (कि "संसाधनों को जल्द से जल्द जारी किया जाता है, क्योंकि आपको उनकी आवश्यकता नहीं है"), लेकिन आप "सभी प्रबंधित भाषाओं में स्वचालित-लेकिन केवल एक विशाल तार्किक छलांग लगा रहे हैं कॉल-स्टैक-आधारित नियतात्मक निपटान के -sort- "। यह सिर्फ पानी पकड़ नहीं है।
हारून

5

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

तो हाँ, मुझे लगता है कि (मैं वास्तव में वहाँ नहीं था ...) यह एक आरामदायक निर्णय था, भाषाओं को आसान बनाने के लक्ष्य के साथ, लेकिन मेरी राय में, यह एक बुरा निर्णय था। फिर से, मैं आम तौर पर C ++ दे-द-प्रोग्रामर्स-ए-मौका-टू-रोल-अपने-अपने दर्शन को पसंद करता हूं, इसलिए मैं थोड़ा पक्षपाती हूं।


7
"दे-ऑफ-प्रोग्रामर्स-ए-मौका-टू-रोल-ही-ही-द फिलॉसफी" काम करता है ठीक यूएनटीआईएल आपको प्रोग्रामर्स द्वारा लिखे गए पुस्तकालयों को संयोजित करने की आवश्यकता है जो प्रत्येक अपने स्वयं के स्ट्रिंग वर्गों और स्मार्ट पॉइंटर्स को रोल करते हैं।
dan04

@ dan04 इसलिए प्रबंधित भाषाएँ जो आपको पूर्व-निर्धारित स्ट्रिंग कक्षाएं देती हैं, फिर आपको बंदर-पैच करने की अनुमति देती हैं, जो कि आपदा का एक नुस्खा है यदि आप उस तरह के आदमी हैं जो अलग-अलग रोल किए गए स्ट्रिंग के साथ सामना नहीं कर सकता है कक्षा।
gbjbaanb

-1

आप पहले से ही C # में इस Disposeविधि के साथ किसी न किसी के बराबर कहते हैं । जावा में भी है finalizeनोट: मुझे पता है कि जावा का अंतिम रूप गैर-नियतात्मक है और इससे अलग है Dispose, मैं सिर्फ यह इंगित कर रहा हूं कि उन दोनों के पास जीसी के साथ-साथ सफाई संसाधनों की एक विधि है।

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

हां C ++ कोड पढ़ने के लिए अधिक सहज हो सकता है, लेकिन डिबग करने के लिए एक बुरा सपना हो सकता है क्योंकि सीमाएं और सीमाएं जो जावा जैसी भाषाएं डालती हैं, वे कुछ अधिक उग्र और कठिन बग के साथ-साथ अन्य डेवलपर्स को सामान्य रोजी गलतियों से बचाती हैं।

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


12
सबसे पहले जावा का "फाइनल" गैर-नियतात्मक है ... यह C # के "डिस्पोज़ल" या C ++ के डिस्ट्रक्टर्स के समतुल्य नहीं है ... साथ ही, C ++ में कचरा संग्रहकर्ता भी है। यदि आप .NET का उपयोग करते हैं
JoanFan

2
@DeadMG: समस्या यह है कि, आप एक बेवकूफ नहीं हो सकते हैं, लेकिन वह दूसरा लड़का जिसने कंपनी छोड़ दी (और जिस कोड को आपने अब बनाए रखा है) लिखा हो सकता है।
केविन

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

3
डेडएमजी ने क्या कहा। C ++ के बारे में कई बुरी बातें हैं। लेकिन RAII उनमें से एक लंबा खिंचाव नहीं है। वास्तव में, जावा और .NET की कमी संसाधन प्रबंधन के लिए ठीक से खाता है (क्योंकि स्मृति एकमात्र संसाधन है, सही?) उनकी सबसे बड़ी समस्याओं में से एक है।
कोनराड रुडोल्फ

8
मेरी राय में अंतिम रूप एक आपदा डिजाइन वार है। जैसा कि आप डिज़ाइनर से ऑब्जेक्ट के उपयोगकर्ता पर ऑब्जेक्ट का सही उपयोग करने के लिए मजबूर कर रहे हैं (स्मृति प्रबंधन के संदर्भ में नहीं बल्कि संसाधन प्रबंधन)। C ++ में संसाधन प्रबंधन को सही (केवल एक बार किया गया) प्राप्त करना कक्षा के डिजाइनर की जिम्मेदारी है। जावा में यह संसाधन प्रबंधन को सही करने के लिए कक्षा के उपयोगकर्ता की जिम्मेदारी है और इस प्रकार हर बार वह वर्ग होना चाहिए जो हमारे द्वारा उपयोग किया जाता है। stackoverflow.com/questions/161177/…
मार्टिन यॉर्क
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.